//++ ------------------------------------------------------------------------------------ // Details: Examine the string and determine if it is a valid string type argument. // Take into account quotes surrounding the text. Note this function falls // through to IsStringArgSingleText() should the criteria match fail. // Type: Method. // Args: vrTxt - (R) Some text. // Return: bool - True = yes valid arg, false = no. // Throws: None. //-- bool CMICmdArgValString::IsStringArgQuotedText( const CMIUtilString & vrTxt ) const { // CODETAG_QUOTEDTEXT_SIMILAR_CODE const MIchar cQuote = '"'; const MIint nPos = vrTxt.find( cQuote ); if( nPos == (MIint) std::string::npos ) return false; // Is one and only quote at end of the string if( nPos == (MIint)(vrTxt.length() - 1) ) return false; // Quote must be the first character in the string or be preceeded by a space // Also check for embedded string formating quote const MIchar cBckSlash = '\\'; const MIchar cSpace = ' '; if( (nPos > 1) && (vrTxt[ nPos - 1 ] == cBckSlash) && (vrTxt[ nPos - 2 ] != cSpace) ) { return false; } if( (nPos > 0) && (vrTxt[ nPos - 1 ] != cSpace) ) return false; // Need to find the other quote const MIint nPos2 = vrTxt.rfind( cQuote ); if( nPos2 == (MIint) std::string::npos ) return false; // Make sure not same quote, need two quotes if( nPos == nPos2 ) return MIstatus::failure; return true; }
//++ ------------------------------------------------------------------------------------ // Details: Write data to existing opened file. // Type: Method. // Args: vData - (R) Text data. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIUtilFileStd::Write( const CMIUtilString & vData ) { if( vData.size() == 0 ) return MIstatus::success; if( m_bFileError ) return MIstatus::failure; if( m_pFileHandle == nullptr ) { m_bFileError = true; SetErrorDescriptionn( MIRSRC( IDE_UTIL_FILE_ERR_WRITING_NOTOPEN ), m_fileNamePath.c_str() ); return MIstatus::failure; } // Get the string size MIuint size = vData.size(); if( ::fwrite( vData.c_str(), 1, size, m_pFileHandle ) == size ) { // Flush the data to the file ::fflush( m_pFileHandle ); return MIstatus::success; } // Not all of the data has been transferred m_bFileError = true; SetErrorDescriptionn( MIRSRC( IDE_UTIL_FILE_ERR_WRITING_FILE ), m_fileNamePath.c_str() ); return MIstatus::failure; }
//++ ------------------------------------------------------------------------------------ // Details: The invoker requires this function. The command does work in this function. // The command is likely to communicate with the LLDB SBDebugger in here. // Type: Overridden. // Args: None. // Return: MIstatus::success - Function succeeded. // MIstatus::failure - Function failed. // Throws: None. //-- bool CMICmdCmdExecArguments::Execute() { CMICMDBASE_GETOPTION(pArgArguments, ListOfN, m_constStrArgArguments); CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); lldb::SBTarget sbTarget = rSessionInfo.GetTarget(); if (!sbTarget.IsValid()) { SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_TARGET_CURRENT), m_cmdData.strMiCmd.c_str())); return MIstatus::failure; } lldb::SBLaunchInfo sbLaunchInfo = sbTarget.GetLaunchInfo(); sbLaunchInfo.SetArguments(NULL, false); CMIUtilString strArg; size_t nArgIndex = 0; while (pArgArguments->GetExpectedOption<CMICmdArgValString, CMIUtilString>(strArg, nArgIndex)) { const char *argv[2] = { strArg.c_str(), NULL }; sbLaunchInfo.SetArguments(argv, true); ++nArgIndex; } sbTarget.SetLaunchInfo(sbLaunchInfo); return MIstatus::success; }
//++ //------------------------------------------------------------------------------------ // Details: The invoker requires this function. The command does work in this // function. // The command is likely to communicate with the LLDB SBDebugger in // here. // Type: Overridden. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmdCmdBreakAfter::Execute() { CMICMDBASE_GETOPTION(pArgNumber, Number, m_constStrArgNamedNumber); CMICMDBASE_GETOPTION(pArgCount, Number, m_constStrArgNamedCount); m_nBrkPtId = pArgNumber->GetValue(); m_nBrkPtCount = pArgCount->GetValue(); CMICmnLLDBDebugSessionInfo &rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance()); lldb::SBBreakpoint brkPt = rSessionInfo.GetTarget().FindBreakpointByID( static_cast<lldb::break_id_t>(m_nBrkPtId)); if (brkPt.IsValid()) { brkPt.SetIgnoreCount(m_nBrkPtCount); CMICmnLLDBDebugSessionInfo::SBrkPtInfo sBrkPtInfo; if (!rSessionInfo.RecordBrkPtInfoGet(m_nBrkPtId, sBrkPtInfo)) { SetError( CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_BRKPT_INFO_OBJ_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_nBrkPtId)); return MIstatus::failure; } sBrkPtInfo.m_nIgnore = m_nBrkPtCount; rSessionInfo.RecordBrkPtInfo(m_nBrkPtId, sBrkPtInfo); } else { const CMIUtilString strBrkPtId(CMIUtilString::Format("%d", m_nBrkPtId)); SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_BRKPT_INVALID), m_cmdData.strMiCmd.c_str(), strBrkPtId.c_str())); return MIstatus::failure; } return MIstatus::success; }
//++ //------------------------------------------------------------------------------------ // Details: The invoker requires this function. The command does work in this // function. // The command is likely to communicate with the LLDB SBDebugger in // here. // Type: Overridden. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmdCmdBreakDelete::Execute() { CMICMDBASE_GETOPTION(pArgBrkPt, ListOfN, m_constStrArgNamedBrkPt); // ATM we only handle one break point ID MIuint64 nBrk = UINT64_MAX; if (!pArgBrkPt->GetExpectedOption<CMICmdArgValNumber, MIuint64>(nBrk)) { SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_BRKPT_INVALID), m_cmdData.strMiCmd.c_str(), m_constStrArgNamedBrkPt.c_str())); return MIstatus::failure; } CMICmnLLDBDebugSessionInfo &rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance()); const bool bBrkPt = rSessionInfo.GetTarget().BreakpointDelete( static_cast<lldb::break_id_t>(nBrk)); if (!bBrkPt) { const CMIUtilString strBrkNum(CMIUtilString::Format("%d", nBrk)); SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_BRKPT_INVALID), m_cmdData.strMiCmd.c_str(), strBrkNum.c_str())); return MIstatus::failure; } return MIstatus::success; }
//++ //------------------------------------------------------------------------------------ // Details: The invoker requires this function. The command does work in this // function. // The command is likely to communicate with the LLDB SBDebugger in // here. // Type: Overridden. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmdCmdBreakCondition::Execute() { CMICMDBASE_GETOPTION(pArgNumber, Number, m_constStrArgNamedNumber); CMICMDBASE_GETOPTION(pArgExpr, String, m_constStrArgNamedExpr); m_nBrkPtId = pArgNumber->GetValue(); m_strBrkPtExpr = pArgExpr->GetValue(); m_strBrkPtExpr += GetRestOfExpressionNotSurroundedInQuotes(); CMICmnLLDBDebugSessionInfo &rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance()); lldb::SBBreakpoint brkPt = rSessionInfo.GetTarget().FindBreakpointByID( static_cast<lldb::break_id_t>(m_nBrkPtId)); if (brkPt.IsValid()) { brkPt.SetCondition(m_strBrkPtExpr.c_str()); CMICmnLLDBDebugSessionInfo::SBrkPtInfo sBrkPtInfo; if (!rSessionInfo.RecordBrkPtInfoGet(m_nBrkPtId, sBrkPtInfo)) { SetError( CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_BRKPT_INFO_OBJ_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_nBrkPtId)); return MIstatus::failure; } sBrkPtInfo.m_strCondition = m_strBrkPtExpr; rSessionInfo.RecordBrkPtInfo(m_nBrkPtId, sBrkPtInfo); } else { const CMIUtilString strBrkPtId(CMIUtilString::Format("%d", m_nBrkPtId)); SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_BRKPT_INVALID), m_cmdData.strMiCmd.c_str(), strBrkPtId.c_str())); return MIstatus::failure; } return MIstatus::success; }
//++ ------------------------------------------------------------------------------------ // Details: Release resources for *this Stdin stream. // Type: Method. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmnStreamStdin::Shutdown(void) { if (--m_clientUsageRefCnt > 0) return MIstatus::success; if (!m_bInitialized) return MIstatus::success; m_bInitialized = false; ClrErrorDescription(); if (m_pCmdBuffer != nullptr) { delete[] m_pCmdBuffer; m_pCmdBuffer = nullptr; } bool bOk = MIstatus::success; CMIUtilString errMsg; MI::ModuleShutdown<CMICmnResources>(IDE_MI_SHTDWN_ERR_RESOURCES, bOk, errMsg); MI::ModuleShutdown<CMICmnLog>(IDS_MI_SHTDWN_ERR_LOG, bOk, errMsg); if (!bOk) { SetErrorDescriptionn(MIRSRC(IDE_MI_SHTDWN_ERR_STREAMSTDIN), errMsg.c_str()); } return MIstatus::success; }
//++ ------------------------------------------------------------------------------------ // Details: A breakpoint expression can be passed to *this command as: // a single string i.e. '2' -> ok. // a quoted string i.e. "a > 100" -> ok // a non quoted string i.e. 'a > 100' -> not ok // CMICmdArgValString only extracts the first space seperated string, the "a". // This function using the optional argument type CMICmdArgValListOfN collects // the rest of the expression so that is may be added to the 'a' part to form a // complete expression string i.e. "a > 100". // If the expression value was guaranteed to be surrounded by quotes them this // function would not be necessary. // Type: Method. // Args: None. // Return: CMIUtilString - Rest of the breakpoint expression. // Throws: None. //-- CMIUtilString CMICmdCmdBreakCondition::GetRestOfExpressionNotSurroundedInQuotes( void ) { CMIUtilString strExpression; CMICmdArgValListOfN * pArgExprNoQuotes = CMICmdBase::GetOption< CMICmdArgValListOfN >( m_constStrArgNamedExprNoQuotes ); if( pArgExprNoQuotes != nullptr ) { CMIUtilString strExpression; const CMICmdArgValListBase::VecArgObjPtr_t & rVecExprParts( pArgExprNoQuotes->GetExpectedOptions() ); if( !rVecExprParts.empty() ) { CMICmdArgValListBase::VecArgObjPtr_t::const_iterator it = rVecExprParts.begin(); while( it != rVecExprParts.end() ) { const CMICmdArgValString * pPartExpr = static_cast< CMICmdArgValString * >( *it ); const CMIUtilString & rPartExpr = pPartExpr->GetValue(); strExpression += " "; strExpression += rPartExpr; // Next ++it; } strExpression = strExpression.Trim(); } } return strExpression; }
//++ ------------------------------------------------------------------------------------ // Details: Examine the string and determine if it is a valid string type argument. // Type: Method. // Args: vrTxt - (R) Some text. // Return: bool - True = yes valid arg, false = no. // Throws: None. //-- bool CMICmdArgValListOfN::IsListOfN(const CMIUtilString &vrTxt) const { CMIUtilString::VecString_t vecOptions; if ((m_eArgType == eArgValType_StringQuoted) || (m_eArgType == eArgValType_StringQuotedNumber) || (m_eArgType == eArgValType_StringQuotedNumberPath) || (m_eArgType == eArgValType_StringAnything)) { if (vrTxt.SplitConsiderQuotes(" ", vecOptions) == 0) return false; } else if (vrTxt.Split(" ", vecOptions) == 0) return false; CMIUtilString::VecString_t::const_iterator it = vecOptions.begin(); while (it != vecOptions.end()) { const CMIUtilString &rOption = *it; if (!IsExpectedCorrectType(rOption, m_eArgType)) break; // Next ++it; } return true; }
//++ // Details: Set MI's error condition description. This may be accessed by // clients and // seen by users. Message is available to the client using the server // and sent // to the Logger. // Type: Method. // Args: vrTxt - (R) Text description. // Return: None. // Throws: None. //-- void CMICmnBase::SetErrorDescription(const CMIUtilString &vrTxt) const { m_strMILastErrorDescription = vrTxt; if (!vrTxt.empty()) { const CMIUtilString txt(CMIUtilString::Format("Error: %s", vrTxt.c_str())); CMICmnStreamStderr::Instance().Write(txt); } }
//++ //------------------------------------------------------------------------------------ // Details: Release resources for *this thread manager. // Type: Method. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmnThreadMgrStd::Shutdown() { if (--m_clientUsageRefCnt > 0) return MIstatus::success; if (!m_bInitialized) return MIstatus::success; m_bInitialized = false; ClrErrorDescription(); bool bOk = MIstatus::success; CMIUtilString errMsg; // Tidy up ThreadAllTerminate(); // Note shutdown order is important here MI::ModuleShutdown<CMICmnResources>(IDE_MI_SHTDWN_ERR_RESOURCES, bOk, errMsg); MI::ModuleShutdown<CMICmnLog>(IDS_MI_SHTDWN_ERR_LOG, bOk, errMsg); if (!bOk) { SetErrorDescriptionn(MIRSRC(IDS_MI_SHUTDOWN_ERR), errMsg.c_str()); } return bOk; }
//++ //------------------------------------------------------------------------------------ // Details: Unregister with the debugger, the SBListener, the type of events you // are no // longer interested in. Others, like commands, may still remain // interested so // an event may not necessarily be stopped. // Type: Method. // Args: vClientName - (R) ID of the client who no longer requires // these events. // vBroadcasterClass - (R) The SBBroadcaster's class name. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebugger::UnregisterForEvent( const CMIUtilString &vClientName, const CMIUtilString &vBroadcasterClass) { MIuint clientsEventMask = 0; if (!ClientGetTheirMask(vClientName, vBroadcasterClass, clientsEventMask)) return MIstatus::failure; if (!ClientRemoveTheirMask(vClientName, vBroadcasterClass)) return MIstatus::failure; const MIuint otherClientsEventMask = ClientGetMaskForAllClients(vBroadcasterClass); MIuint newEventMask = 0; for (MIuint i = 0; i < 32; i++) { const MIuint bit = 1 << i; const MIuint clientBit = bit & clientsEventMask; const MIuint othersBit = bit & otherClientsEventMask; if ((clientBit != 0) && (othersBit == 0)) { newEventMask += clientBit; } } const char *pBroadCasterName = vBroadcasterClass.c_str(); if (!m_lldbListener.StopListeningForEventClass( m_lldbDebugger, pBroadCasterName, newEventMask)) { SetErrorDescription( CMIUtilString::Format(MIRSRC(IDS_LLDBDEBUGGER_ERR_STOPLISTENER), vClientName.c_str(), pBroadCasterName)); return MIstatus::failure; } return BroadcasterSaveMask(vBroadcasterClass, otherClientsEventMask); }
//++ ------------------------------------------------------------------------------------ // Details: Release resources for *this Stdin stream. // Type: Method. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmnStreamStdinLinux::Shutdown( void ) { if( !m_bInitialized ) return MIstatus::success; m_bInitialized = false; ClrErrorDescription(); bool bOk = MIstatus::success; CMIUtilString errMsg; // Tidy up if( m_pCmdBuffer != nullptr ) { delete [] m_pCmdBuffer; m_pCmdBuffer = nullptr; } m_pStdin = nullptr; // Note shutdown order is important here MI::ModuleShutdown< CMICmnResources >( IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg ); MI::ModuleShutdown< CMICmnLog > ( IDS_MI_INIT_ERR_LOG , bOk, errMsg ); if( !bOk ) { SetErrorDescriptionn( MIRSRC( IDS_MI_SHTDWN_ERR_OS_STDIN_HANDLER ), errMsg.c_str() ); } return MIstatus::success; }
//++ //------------------------------------------------------------------------------------ // Details: Initialise resources for *this thread manager. // Type: Method. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmnThreadMgrStd::Initialize() { m_clientUsageRefCnt++; if (m_bInitialized) return MIstatus::success; bool bOk = MIstatus::success; ClrErrorDescription(); CMIUtilString errMsg; // Note initialisation order is important here as some resources depend on // previous MI::ModuleInit<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg); MI::ModuleInit<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg); m_bInitialized = bOk; if (!bOk) { CMIUtilString strInitError(CMIUtilString::Format( MIRSRC(IDS_MI_INIT_ERR_THREADMGR), errMsg.c_str())); SetErrorDescription(strInitError); return MIstatus::failure; } return bOk; }
//++ ------------------------------------------------------------------------------------ // Details: Form MI partial response by appending more MI value type objects to the // tuple type object past in. // Type: Method. // Args: vPc - (R) Address number. // vFnName - (R) Function name. // vFileName - (R) File name text. // vPath - (R) Full file name and path text. // vnLine - (R) File line number. // vwrMIValueTuple - (W) MI value tuple object. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmnLLDBDebugSessionInfo::MIResponseFormBrkPtFrameInfo( const lldb::addr_t vPc, const CMIUtilString & vFnName, const CMIUtilString & vFileName, const CMIUtilString & vPath, const MIuint vnLine, CMICmnMIValueTuple & vwrMiValueTuple ) { const CMIUtilString strAddr( CMIUtilString::Format( "0x%08llx", vPc ) ); const CMICmnMIValueConst miValueConst2( strAddr ); const CMICmnMIValueResult miValueResult2( "addr", miValueConst2 ); if( !vwrMiValueTuple.Add( miValueResult2 ) ) return MIstatus::failure; const CMICmnMIValueConst miValueConst3( vFnName ); const CMICmnMIValueResult miValueResult3( "func", miValueConst3 ); if( !vwrMiValueTuple.Add( miValueResult3 ) ) return MIstatus::failure; const CMICmnMIValueConst miValueConst5( vFileName ); const CMICmnMIValueResult miValueResult5( "file", miValueConst5 ); if( !vwrMiValueTuple.Add( miValueResult5 ) ) return MIstatus::failure; const CMIUtilString strN5 = CMIUtilString::Format( "%s/%s", vPath.c_str(), vFileName.c_str() ); const CMICmnMIValueConst miValueConst6( strN5 ); const CMICmnMIValueResult miValueResult6( "fullname", miValueConst6 ); if( !vwrMiValueTuple.Add( miValueResult6 ) ) return MIstatus::failure; const CMIUtilString strLine( CMIUtilString::Format( "%d", vnLine ) ); const CMICmnMIValueConst miValueConst7( strLine ); const CMICmnMIValueResult miValueResult7( "line", miValueConst7 ); if( !vwrMiValueTuple.Add( miValueResult7 ) ) return MIstatus::failure; return MIstatus::success; }
//++ ------------------------------------------------------------------------------------ // Details: Create list of argument objects each holding a value extract from the command // options line. // Type: Method. // Args: vrTxt - (R) Some options text. // Return: bool - True = yes valid arg, false = no. // Throws: None. //-- bool CMICmdArgValListOfN::CreateList(const CMIUtilString &vrTxt) { CMIUtilString::VecString_t vecOptions; if ((m_eArgType == eArgValType_StringQuoted) || (m_eArgType == eArgValType_StringQuotedNumber) || (m_eArgType == eArgValType_StringQuotedNumberPath) || (m_eArgType == eArgValType_StringAnything)) { if (vrTxt.SplitConsiderQuotes(" ", vecOptions) == 0) return MIstatus::failure; } else if (vrTxt.Split(" ", vecOptions) == 0) return MIstatus::failure; CMIUtilString::VecString_t::const_iterator it = vecOptions.begin(); while (it != vecOptions.end()) { const CMIUtilString &rOption = *it; CMICmdArgValBase *pOption = CreationObj(rOption, m_eArgType); if (pOption != nullptr) m_argValue.push_back(pOption); else return MIstatus::failure; // Next ++it; } return MIstatus::success; }
//++ ------------------------------------------------------------------------------------ // Details: Parse the command's argument options string and try to extract all the words // between quotes then delimited by the next space. If there any string format // characters '\\' used to embed quotes these are ignored i.e. "\\\"%5d\\\"" // becomes "%5d". // Type: Method. // Args: vrwArgContext - (RW) The command's argument options string. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmdArgValString::ValidateQuotedQuotedTextEmbedded( CMICmdArgContext & vrwArgContext ) { // CODETAG_QUOTEDTEXT_SIMILAR_CODE CMIUtilString strOptions = vrwArgContext.GetArgsLeftToParse(); const MIint nPos = strOptions.find( "\"\\\"" ); if( nPos == (MIint) std::string::npos ) return MIstatus::failure; const MIint nPos2 = strOptions.rfind( "\\\"\"" ); if( nPos2 == (MIint) std::string::npos ) return MIstatus::failure; const MIint nLen = strOptions.length(); if( (nLen > 5) && ((nPos + 2) == (nPos2 - 2)) ) return MIstatus::failure; // Quote must be the first character in the string or be preceeded by a space // or '\\' const MIchar cSpace = ' '; if( (nPos > 0) && (strOptions[ nPos - 1 ] != cSpace) ) return MIstatus::failure; // Extract quoted text const CMIUtilString strQuotedTxt = strOptions.substr( nPos, nPos2 - nPos + 3 ).c_str(); if( vrwArgContext.RemoveArg( strQuotedTxt ) ) { m_bFound = true; m_bValid = true; m_argValue = strQuotedTxt; return MIstatus::success; } return MIstatus::failure; }
//++ ------------------------------------------------------------------------------------ // 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 invalid, false = command acted on. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIDriver::InterpretCommandThisDriver( const CMIUtilString & vTextLine, bool & vwbCmdYesValid ) { vwbCmdYesValid = false; bool bCmdNotInCmdFactor = false; SMICmdData cmdData; CMICmdMgr & rCmdMgr = CMICmdMgr::Instance(); if( !rCmdMgr.CmdInterpret( vTextLine, vwbCmdYesValid, bCmdNotInCmdFactor, cmdData ) ) return MIstatus::failure; if( vwbCmdYesValid ) { // For debugging only //m_pLog->WriteLog( cmdData.strMiCmdAll.c_str() ); return ExecuteCommand( cmdData ); } // 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 ), vTextLine.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 ); m_rStdOut.WriteMIResponse( miResultRecord.GetString() ); // Proceed to wait for or execute next command return MIstatus::success; }
//++ ------------------------------------------------------------------------------------ // 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(void) { 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: Determine and form the medium file's directory path and name. // Type: Method. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmnLogMediumFile::FileFormFileNamePath( void ) { ClrErrorDescription(); m_fileNamePath = MIRSRC( IDS_MEDIUMFILE_ERR_INVALID_PATH ); CMIUtilString strPathName; if( CMIUtilSystem().GetLogFilesPath( strPathName ) ) { const CMIUtilString strPath = CMIUtilFileStd().StripOffFileName( strPathName ); // ToDo: Review this LINUX log file quick fix so not hidden // AD: // Linux was creating a log file here called '.\log.txt'. The '.' on linux // signifies that this file is 'hidden' and not normally visible. A quick fix // is to remove the path component all together. Linux also normally uses '/' // as directory separators, again leading to the problem of the hidden log. #if defined ( _MSC_VER ) m_fileNamePath = CMIUtilString::Format( "%s\\%s", strPath.c_str(), m_constMediumFileName.c_str() ); #else m_fileNamePath = CMIUtilString::Format( "%s", m_constMediumFileName.c_str() ); #endif // defined ( _MSC_VER ) return MIstatus::success; } SetErrorDescription( MIRSRC( IDE_MEDIUMFILE_ERR_GET_FILE_PATHNAME_SYS ) ); return MIstatus::failure; }
//++ ------------------------------------------------------------------------------------ // Details: Write text data to stderr. The text data does not need to // include a carriage line return as this is added to the text. The function also // then passes the text data into the CMICmnLog logger. // Type: Method. // Args: vText - (R) Text data. May be prefixed with MI app's short name. // vTxtForLogFile - (R) Text data. // vbSendToLog - (R) True = Yes send to the Log file too, false = do not. (Dflt = true) // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmnStreamStderr::WritePriv(const CMIUtilString &vText, const CMIUtilString &vTxtForLogFile, const bool vbSendToLog /* = true */) { if (vText.length() == 0) return MIstatus::failure; bool bOk = MIstatus::success; { // Grab the stderr thread lock while we print CMIUtilThreadLock _lock(m_mutex); // Send this text to stderr const MIint status = ::fputs(vText.c_str(), stderr); if (status == EOF) { const CMIUtilString errMsg(CMIUtilString::Format(MIRSRC(IDS_STDERR_ERR_NOT_ALL_DATA_WRITTEN), vText.c_str())); SetErrorDescription(errMsg); bOk = MIstatus::failure; } else { ::fprintf(stderr, "\n"); ::fflush(stderr); } // Send this text to the log if (bOk && vbSendToLog) bOk &= m_pLog->WriteLog(vTxtForLogFile); } return bOk; }
//++ // Details: Check if two strings share equal contents. // Type: Method. // Args: vrLhs - (R) String A. // vrRhs - (R) String B. // Return: bool - True = yes equal, false - different. // Throws: None. //-- bool CMIUtilString::Compare(const CMIUtilString &vrLhs, const CMIUtilString &vrRhs) { // Check the sizes match if (vrLhs.size() != vrRhs.size()) return false; return (::strncmp(vrLhs.c_str(), vrRhs.c_str(), vrLhs.size()) == 0); }
//++ //------------------------------------------------------------------------------------ // Details: Show a dialog to the process/application halts. It gives the // opportunity to // attach a debugger. // Type: Static method. // Args: None. // Return: None. // Throws: None. //-- void CMIUtilDebug::ShowDlgWaitForDbgAttach() { const CMIUtilString strCaption(CMIDriver::Instance().GetAppNameShort()); #ifdef _WIN32 ::MessageBoxA(NULL, "Attach your debugger now", strCaption.c_str(), MB_OK); #else // ToDo: Implement other platform version of an Ok to continue dialog box #endif // _WIN32 }
@@ -509,7 +509,7 @@ bool CMIDriver::StartWorkerThreads() { const CMIUtilString errMsg = CMIUtilString::Format( MIRSRC(IDS_THREADMGR_ERR_THREAD_FAIL_CREATE), CMICmnThreadMgrStd::Instance().GetErrorDescription().c_str()); - SetErrorDescriptionn(errMsg); + SetErrorDescriptionn(errMsg.c_str()); return MIstatus::failure; }
//++ ------------------------------------------------------------------------------------ // 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: Write an LLDB text message to stderr. // The text data does not need to include a carrage line return as this is added // to the text. The function also then passes the text data into the CMICmnLog // logger. // Type: Method. // Args: vText - (R) Text data. // vbSendToLog - (R) True = Yes send to the Log file too, false = do not. (Dflt = true) // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmnStreamStderr::WriteLLDBMsg( const CMIUtilString & vText, const bool vbSendToLog /* = true */ ) { if( vText.length() == 0 ) return MIstatus::failure; const CMIUtilString strPrefixed( CMIUtilString::Format( "LLDB: %s", vText.c_str() ) ); return WritePriv( vText, strPrefixed, vbSendToLog ); }
//++ ------------------------------------------------------------------------------------ // 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( void ) { 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 ); #if MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER CMIDriverMgr & rDrvMgr = CMIDriverMgr::Instance(); bOk = bOk && rDrvMgr.RegisterDriver( *g_driver, "LLDB driver" ); // Will be pass thru driver if( bOk ) { bOk = SetEnableFallThru( false ); // This is intentional at this time - yet to be fully implemented bOk = bOk && SetDriverToFallThruTo( *g_driver ); CMIUtilString strOtherDrvErrMsg; if( bOk && GetEnableFallThru() && !g_driver->MISetup( strOtherDrvErrMsg ) ) { bOk = false; errMsg = CMIUtilString::Format( MIRSRC( IDS_MI_INIT_ERR_FALLTHRUDRIVER ), strOtherDrvErrMsg.c_str() ); } } #endif // MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER m_bExitApp = false; bOk = bOk && InitClientIDEToMIDriver(); // Init Eclipse IDE 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: Remove the argument from the options text and any space after the argument // if applicable. // Type: Method. // Args: vArg - (R) The name of the argument. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmdArgContext::RemoveArg(const CMIUtilString &vArg) { if (vArg.empty()) return MIstatus::success; const size_t nLen = vArg.length(); const size_t nLenCntxt = m_strCmdArgsAndOptions.length(); if (nLen > nLenCntxt) return MIstatus::failure; size_t nExtraSpace = 0; size_t nPos = m_strCmdArgsAndOptions.find(vArg); while (1) { if (nPos == std::string::npos) return MIstatus::success; bool bPass1 = false; if (nPos != 0) { if (m_strCmdArgsAndOptions[nPos - 1] == ' ') bPass1 = true; } else bPass1 = true; const size_t nEnd = nPos + nLen; if (bPass1) { bool bPass2 = false; if (nEnd < nLenCntxt) { if (m_strCmdArgsAndOptions[nEnd] == ' ') { bPass2 = true; nExtraSpace = 1; } } else bPass2 = true; if (bPass2) break; } nPos = m_strCmdArgsAndOptions.find(vArg, nEnd); } const size_t nPosEnd = nLen + nExtraSpace; m_strCmdArgsAndOptions = m_strCmdArgsAndOptions.replace(nPos, nPosEnd, ""); m_strCmdArgsAndOptions = m_strCmdArgsAndOptions.Trim(); return MIstatus::success; }
//++ ------------------------------------------------------------------------------------ // Details: Determine the given file path exists or not. // Type: Method. // Args: vPath - (R) File name path. // vwbYesAccessible - (W) True - file exists, false = does not exist. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmnLLDBDebugSessionInfo::AccessPath( const CMIUtilString & vPath, bool & vwbYesAccessible ) { #ifdef _WIN32 vwbYesAccessible = (::_access( vPath.c_str(), 0 ) == 0); #else vwbYesAccessible = (::access( vPath.c_str(), 0 ) == 0); #endif // _WIN32 return MIstatus::success; }
//++ ------------------------------------------------------------------------------------ // Details: Initialize resources for *this debugger object. // Type: Method. // Args: None. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebugger::Initialize() { m_clientUsageRefCnt++; if (m_bInitialized) return MIstatus::success; bool bOk = MIstatus::success; CMIUtilString errMsg; ClrErrorDescription(); if (m_pClientDriver == nullptr) { bOk = false; errMsg = MIRSRC(IDS_LLDBDEBUGGER_ERR_CLIENTDRIVER); } // Note initialization order is important here as some resources depend on previous MI::ModuleInit<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg); MI::ModuleInit<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg); MI::ModuleInit<CMICmnThreadMgrStd>(IDS_MI_INIT_ERR_THREADMGR, bOk, errMsg); MI::ModuleInit<CMICmnLLDBDebuggerHandleEvents>(IDS_MI_INIT_ERR_OUTOFBANDHANDLER, bOk, errMsg); MI::ModuleInit<CMICmnLLDBDebugSessionInfo>(IDS_MI_INIT_ERR_DEBUGSESSIONINFO, bOk, errMsg); // Note order is important here! if (bOk) lldb::SBDebugger::Initialize(); if (bOk && !InitSBDebugger()) { bOk = false; if (!errMsg.empty()) errMsg += ", "; errMsg += GetErrorDescription().c_str(); } if (bOk && !InitSBListener()) { bOk = false; if (!errMsg.empty()) errMsg += ", "; errMsg += GetErrorDescription().c_str(); } bOk = bOk && InitStdStreams(); bOk = bOk && RegisterMISummaryProviders(); m_bInitialized = bOk; if (!bOk && !HaveErrorDescription()) { CMIUtilString strInitError(CMIUtilString::Format(MIRSRC(IDS_MI_INIT_ERR_LLDBDEBUGGER), errMsg.c_str())); SetErrorDescription(strInitError); } return bOk; }