//++ ------------------------------------------------------------------------------------ // Details: Execute commands from prepared source file // 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: 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: Command instances can create and share data between other instances of commands. // This function adds new data to the shared data. Using the same ID more than // once replaces any previous matching data keys. // Type: Method. // Args: vKey - (R) A non empty unique data key to retrieve by. // vData - (R) Data to be added to the share. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmnLLDBDebugSessionInfo::SharedDataAdd( const CMIUtilString & vKey, const CMIUtilString & vData ) { if( vKey.empty() ) return MIstatus::failure; MapPairKeyToStringValue_t pr( vKey, vData ); m_mapKeyToStringValue.insert( pr ); return MIstatus::success; }
//++ ------------------------------------------------------------------------------------ // 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 Driver::SetId( const CMIUtilString & vId ) { if( vId.empty() ) { // Invalid to have it empty return MIstatus::failure; } m_strDriverId = vId; return MIstatus::success; }
//++ ------------------------------------------------------------------------------------ // 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: Given the SBBroadcaster class name save it's current event mask. // Type: Method. // Args: vBroadcasterClass - (R) The SBBroadcaster's class name. // vEventMask - (R) The mask of events to listen for. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebugger::BroadcasterSaveMask( const CMIUtilString & vBroadcasterClass, const MIuint vEventMask ) { if( vBroadcasterClass.empty() ) { SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_INVALIDBROADCASTER ), vBroadcasterClass.c_str() ) ); return MIstatus::failure; } BroadcasterRemoveMask( vBroadcasterClass ); MapPairBroadcastClassNameToEventMask_t pr( vBroadcasterClass, vEventMask ); m_mapBroadcastClassNameToEventMask.insert( pr ); return MIstatus::success; }
//++ ------------------------------------------------------------------------------------ // Details: Validate and set the text that forms the prompt on the command line. // Type: Method. // Args: vNewPrompt - (R) Text description. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmnStreamStdin::SetPrompt(const CMIUtilString &vNewPrompt) { if (vNewPrompt.empty()) { const CMIUtilString msg(CMIUtilString::Format(MIRSRC(IDS_STDIN_ERR_INVALID_PROMPT), vNewPrompt.c_str())); CMICmnStreamStdout::Instance().Write(msg); return MIstatus::failure; } m_strPromptCurrent = vNewPrompt; return MIstatus::success; }
//++ ------------------------------------------------------------------------------------ // Details: Status on a file existing already. // Type: Method. // Args: vFileNamePath. // Return: True - Exists. // False - Not found. // Throws: None. //-- bool CMIUtilFileStd::IsFileExist( const CMIUtilString & vFileNamePath ) const { if( vFileNamePath.empty() ) return false; FILE * pTmp = nullptr; pTmp = ::fopen( vFileNamePath.c_str(), "wb" ); if( pTmp != nullptr ) { ::fclose( pTmp ); return true; } return false; }
//++ ------------------------------------------------------------------------------------ // Details: Check a command's name is valid: // - name is not empty // - name does not have spaces // Type: Method. // Args: vMiCmd - (R) Command's name, the MI command. // Return: True - valid. // False - not valid. // Throws: None. //-- bool CMICmdFactory::IsValid( const CMIUtilString & vMiCmd ) const { bool bValid = true; if( vMiCmd.empty() ) { bValid = false; return false; } const MIint nPos = vMiCmd.find( " " ); if( nPos != (MIint) std::string::npos ) bValid = false; return bValid; }
//++ ------------------------------------------------------------------------------------ // Details: *this driver sits and waits for input to the stdin line queue shared by *this // driver and the stdin monitor thread, it queues, *this reads, interprets and // reacts. // 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::ReadStdinLineQueue( void ) { // True when queue contains input bool bHaveInput = false; // Stores the current input line CMIUtilString lineText; { // Lock while we access the queue CMIUtilThreadLock lock( m_threadMutex ); if( !m_queueStdinLine.empty() ) { lineText = m_queueStdinLine.front(); m_queueStdinLine.pop(); bHaveInput = !lineText.empty(); } } // Process while we have input if( bHaveInput ) { if( lineText == "quit" ) { // We want to be exiting when receiving a quit command m_bExitApp = true; return MIstatus::success; } // Process the command const bool bOk = InterpretCommand( lineText ); // Draw prompt if desired if( bOk && m_rStdin.GetEnablePrompt() ) m_rStdOut.WriteMIResponse( m_rStdin.GetPrompt() ); // Input has been processed bHaveInput = false; } else { // Give resources back to the OS const std::chrono::milliseconds time( 1 ); std::this_thread::sleep_for( time ); } return MIstatus::success; }
//++ ------------------------------------------------------------------------------------ // Details: Given the client save its particular event requirements. // Type: Method. // Args: vClientName - (R) The Client's unique ID. // vBroadcasterClass - (R) The SBBroadcaster's class name targeted for the events. // vEventMask - (R) The mask of events to listen for. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebugger::ClientSaveMask( const CMIUtilString & vClientName, const CMIUtilString & vBroadcasterClass, const MIuint vEventMask ) { if( vClientName.empty() ) { SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_INVALIDCLIENTNAME ), vClientName.c_str() ) ); return MIstatus::failure; } CMIUtilString strId( vBroadcasterClass ); strId += vClientName; ClientRemoveTheirMask( vClientName, vBroadcasterClass ); MapPairIdToEventMask_t pr( strId, vEventMask ); m_mapIdToEventMask.insert( pr ); return MIstatus::success; }
//++ //------------------------------------------------------------------------------------ // Details: Given the client remove it's particular event requirements. // Type: Method. // Args: vClientName - (R) The Client's unique ID. // vBroadcasterClass - (R) The SBBroadcaster's class name. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebugger::ClientRemoveTheirMask( const CMIUtilString &vClientName, const CMIUtilString &vBroadcasterClass) { if (vClientName.empty()) { SetErrorDescription(CMIUtilString::Format( MIRSRC(IDS_LLDBDEBUGGER_ERR_INVALIDCLIENTNAME), vClientName.c_str())); return MIstatus::failure; } CMIUtilString strId(vBroadcasterClass); strId += vClientName; const MapIdToEventMask_t::const_iterator it = m_mapIdToEventMask.find(strId); if (it != m_mapIdToEventMask.end()) { m_mapIdToEventMask.erase(it); } return MIstatus::success; }
//++ ------------------------------------------------------------------------------------ // Details: Given the SBBroadcaster class name retrieve it's current event mask. // Type: Method. // Args: vBroadcasterClass - (R) The SBBroadcaster's class name. // vEventMask - (W) The mask of events to listen for. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebugger::BroadcasterGetMask( const CMIUtilString & vBroadcasterClass, MIuint & vwEventMask ) const { vwEventMask = 0; if( vBroadcasterClass.empty() ) { SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_INVALIDBROADCASTER ), vBroadcasterClass.c_str() ) ); return MIstatus::failure; } const MapBroadcastClassNameToEventMask_t::const_iterator it = m_mapBroadcastClassNameToEventMask.find( vBroadcasterClass ); if( it != m_mapBroadcastClassNameToEventMask.end() ) { vwEventMask = (*it).second; } return MIstatus::success; }
//++ ------------------------------------------------------------------------------------ // 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) Error description on command failing. // Return: MIstatus::success - Command succeeded. // MIstatus::failure - Command failed. // Throws: None. //-- bool Driver::DoFallThruToAnotherDriver( const CMIUtilString & vCmd, CMIUtilString & vwErrMsg ) { bool bOk = MIstatus::success; vwErrMsg.empty(); // ToDo: Implement do work on other driver after this driver said "Give up you try" // This may nto be required if the feature to 'fall through' is not required SBCommandReturnObject returnObj = lldb::SBCommandReturnObject(); SBCommandInterpreter cmdIntrp = m_debugger.GetCommandInterpreter(); const lldb::ReturnStatus cmdResult = cmdIntrp.HandleCommand( vCmd.c_str(), returnObj ); MIunused( cmdResult ); if( returnObj.Succeeded() == false ) { bOk = MIstatus::failure; vwErrMsg = returnObj.GetError(); } return bOk; }
//++ // Details: Find and replace all matches of a sub string with another string. It // does not // alter *this string. // Type: Method. // Args: vFind - (R) The string to look for. // vReplaceWith - (R) The string to replace the vFind match. // Return: CMIUtilString - New version of the string. // Throws: None. //-- CMIUtilString CMIUtilString::FindAndReplace(const CMIUtilString &vFind, const CMIUtilString &vReplaceWith) const { if (vFind.empty() || this->empty()) return *this; size_t nPos = find(vFind); if (nPos == std::string::npos) return *this; CMIUtilString strNew(*this); while (nPos != std::string::npos) { strNew.replace(nPos, vFind.length(), vReplaceWith); nPos += vReplaceWith.length(); nPos = strNew.find(vFind, nPos); } return strNew; }
//++ ------------------------------------------------------------------------------------ // Details: Splits string into array of strings using delimiter. If multiple delimiter // are found in sequence then they are not added to the list of splits. // Type: Method. // Args: vData - (R) String data to be split up. // vDelimiter - (R) Delimiter char or text. // vwVecSplits - (W) Container of splits found in string data. // Return: MIuint - Number of splits found in the string data. // Throws: None. //-- MIuint CMIUtilString::Split( const CMIUtilString & vDelimiter, VecString_t & vwVecSplits ) const { vwVecSplits.clear(); if( this->empty() || vDelimiter.empty() ) return 0; MIint nPos = find( vDelimiter ); if( nPos == (MIint) std::string::npos ) { vwVecSplits.push_back( *this ); return 1; } const MIint strLen( length() ); if( nPos == strLen ) { vwVecSplits.push_back( *this ); return 1; } MIuint nAdd1( 1 ); if( (nPos > 0) && (substr( 0, nPos ) != vDelimiter) ) { nPos = 0; nAdd1 = 0; } MIint nPos2 = find( vDelimiter, nPos + 1 ); while( nPos2 != (MIint) std::string::npos ) { const MIuint len( nPos2 - nPos - nAdd1 ); const std::string strSection( substr( nPos + nAdd1, len ) ); if( strSection != vDelimiter ) vwVecSplits.push_back( strSection.c_str() ); nPos += len + 1; nPos2 = find( vDelimiter, nPos + 1 ); nAdd1 = 0; } const std::string strSection( substr( nPos, strLen - nPos ) ); if( (strSection.length() != 0) && (strSection != vDelimiter) ) vwVecSplits.push_back( strSection.c_str() ); return vwVecSplits.size(); }
//++ ------------------------------------------------------------------------------------ // Details: Splits string into array of strings using delimiter. However the string is // also considered for text surrounded by quotes. Text with quotes including the // delimiter is treated as a whole. If multiple delimiter are found in sequence // then they are not added to the list of splits. Quotes that are embedded in // the string as string formatted quotes are ignored (proceeded by a '\\') i.e. // "\"MI GDB local C++.cpp\":88". // Type: Method. // Args: vData - (R) String data to be split up. // vDelimiter - (R) Delimiter char or text. // vwVecSplits - (W) Container of splits found in string data. // Return: size_t - Number of splits found in the string data. // Throws: None. //-- size_t CMIUtilString::SplitConsiderQuotes(const CMIUtilString &vDelimiter, VecString_t &vwVecSplits) const { vwVecSplits.clear(); if (this->empty() || vDelimiter.empty()) return 0; const size_t nLen(length()); size_t nOffset(0); do { // Find first occurrence which doesn't match to the delimiter const size_t nSectionPos(FindFirstNot(vDelimiter, nOffset)); if (nSectionPos == std::string::npos) break; // Find next occurrence of the delimiter after (quoted) section const bool bSkipQuotedText(true); bool bUnmatchedQuote(false); size_t nNextDelimiterPos(FindFirst(vDelimiter, bSkipQuotedText, bUnmatchedQuote, nSectionPos)); if (bUnmatchedQuote) { vwVecSplits.clear(); return 0; } if (nNextDelimiterPos == std::string::npos) nNextDelimiterPos = nLen; // Extract string between delimiters const size_t nSectionLen(nNextDelimiterPos - nSectionPos); const std::string strSection(substr(nSectionPos, nSectionLen)); vwVecSplits.push_back(strSection.c_str()); // Next nOffset = nNextDelimiterPos + 1; } while (nOffset < nLen); return vwVecSplits.size(); }
//++ //------------------------------------------------------------------------------------ // Details: Retrieve the client's event mask used for on a particular // SBBroadcaster. // Type: Method. // Args: vClientName - (R) The Client's unique ID. // vBroadcasterClass - (R) The SBBroadcaster's class name. // vwEventMask - (W) The client's mask. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebugger::ClientGetTheirMask( const CMIUtilString &vClientName, const CMIUtilString &vBroadcasterClass, MIuint &vwEventMask) { vwEventMask = 0; if (vClientName.empty()) { SetErrorDescription(CMIUtilString::Format( MIRSRC(IDS_LLDBDEBUGGER_ERR_INVALIDCLIENTNAME), vClientName.c_str())); return MIstatus::failure; } const CMIUtilString strId(vBroadcasterClass + vClientName); const MapIdToEventMask_t::const_iterator it = m_mapIdToEventMask.find(strId); if (it != m_mapIdToEventMask.end()) { vwEventMask = (*it).second; } SetErrorDescription(CMIUtilString::Format( MIRSRC(IDS_LLDBDEBUGGER_ERR_CLIENTNOTREGISTERED), vClientName.c_str())); return MIstatus::failure; }
//++ //------------------------------------------------------------------------------------ // Details: Retrieve from the LLDB SB Value object the value of the variable // described in // text if it has a simple format (not composite). // Type: Method. // Args: vwrValue - (W) The SBValue in a string format. // Return: MIstatus::success - Function succeeded. // MIstatus::failure - Function failed. // Throws: None. //-- bool CMICmnLLDBUtilSBValue::GetSimpleValue(const bool vbHandleArrayType, CMIUtilString &vwrValue) const { const MIuint nChildren = m_rValue.GetNumChildren(); if (nChildren == 0) { vwrValue = GetValueSummary(!m_bHandleCharType && IsCharType(), m_pUnkwn); return MIstatus::success; } else if (IsPointerType()) { vwrValue = GetValueSummary(!m_bHandleCharType && IsPointeeCharType(), m_pUnkwn); return MIstatus::success; } else if (IsArrayType()) { CMICmnLLDBDebugSessionInfo &rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance()); bool bPrintCharArrayAsString = false; bPrintCharArrayAsString = rSessionInfo.SharedDataRetrieve<bool>( rSessionInfo.m_constStrPrintCharArrayAsString, bPrintCharArrayAsString) && bPrintCharArrayAsString; if (bPrintCharArrayAsString && m_bHandleCharType && IsFirstChildCharType()) { vwrValue = GetValueSummary(false); return MIstatus::success; } else if (vbHandleArrayType) { vwrValue = CMIUtilString::Format("[%u]", nChildren); return MIstatus::success; } } else { // Treat composite value which has registered summary // (for example with AddCXXSummary) as simple value vwrValue = GetValueSummary(false); if (!vwrValue.empty()) return MIstatus::success; } // Composite variable type i.e. struct return MIstatus::failure; }
//++ ------------------------------------------------------------------------------------ // Details: Open file for writing. On the first call to this function after *this object // is created the file is either created or replace, from then on open only opens // an existing file. // Type: Method. // Args: vFileNamePath - (R) File name path. // vwrbNewCreated - (W) True - file recreated, false - file appended too. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIUtilFileStd::CreateWrite( const CMIUtilString & vFileNamePath, bool & vwrbNewCreated ) { // Reset m_bFileError = false; vwrbNewCreated = false; if( vFileNamePath.empty() ) { m_bFileError = true; SetErrorDescription( MIRSRC( IDS_UTIL_FILE_ERR_INVALID_PATHNAME ) ); return MIstatus::failure; } // File is already open so exit if( m_pFileHandle != nullptr ) return MIstatus::success; #if !defined( _MSC_VER ) // Open with 'write' and 'binary' mode m_pFileHandle = ::fopen( vFileNamePath.c_str(), "wb" ); #else // Open a file with exclusive write and shared read permissions m_pFileHandle = ::_fsopen( vFileNamePath.c_str(), "wb", _SH_DENYWR ); #endif // !defined( _MSC_VER ) if( m_pFileHandle == nullptr ) { m_bFileError = true; SetErrorDescriptionn( MIRSRC( IDS_UTIL_FILE_ERR_OPENING_FILE ), strerror( errno ), vFileNamePath.c_str() ); return MIstatus::failure; } vwrbNewCreated = true; m_fileNamePath = vFileNamePath; 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 CMICmdCmdBreakInsert::Execute() { CMICMDBASE_GETOPTION(pArgTempBrkPt, OptionShort, m_constStrArgNamedTempBrkPt); CMICMDBASE_GETOPTION(pArgThreadGroup, OptionLong, m_constStrArgNamedThreadGroup); CMICMDBASE_GETOPTION(pArgLocation, String, m_constStrArgNamedLocation); CMICMDBASE_GETOPTION(pArgIgnoreCnt, OptionShort, m_constStrArgNamedInoreCnt); CMICMDBASE_GETOPTION(pArgPendingBrkPt, OptionShort, m_constStrArgNamedPendinfBrkPt); CMICMDBASE_GETOPTION(pArgDisableBrkPt, OptionShort, m_constStrArgNamedDisableBrkPt); CMICMDBASE_GETOPTION(pArgConditionalBrkPt, OptionShort, m_constStrArgNamedConditionalBrkPt); CMICMDBASE_GETOPTION(pArgRestrictBrkPtToThreadId, OptionShort, m_constStrArgNamedRestrictBrkPtToThreadId); m_bBrkPtEnabled = !pArgDisableBrkPt->GetFound(); m_bBrkPtIsTemp = pArgTempBrkPt->GetFound(); m_bHaveArgOptionThreadGrp = pArgThreadGroup->GetFound(); if (m_bHaveArgOptionThreadGrp) { MIuint nThreadGrp = 0; pArgThreadGroup->GetExpectedOption<CMICmdArgValThreadGrp, MIuint>(nThreadGrp); m_strArgOptionThreadGrp = CMIUtilString::Format("i%d", nThreadGrp); } m_bBrkPtIsPending = pArgPendingBrkPt->GetFound(); if (pArgLocation->GetFound()) m_brkName = pArgLocation->GetValue(); else if (m_bBrkPtIsPending) { pArgPendingBrkPt->GetExpectedOption<CMICmdArgValString, CMIUtilString>(m_brkName); } if (pArgIgnoreCnt->GetFound()) { pArgIgnoreCnt->GetExpectedOption<CMICmdArgValNumber, MIuint>(m_nBrkPtIgnoreCount); } m_bBrkPtCondition = pArgConditionalBrkPt->GetFound(); if (m_bBrkPtCondition) { pArgConditionalBrkPt->GetExpectedOption<CMICmdArgValString, CMIUtilString>(m_brkPtCondition); } m_bBrkPtThreadId = pArgRestrictBrkPtToThreadId->GetFound(); if (m_bBrkPtCondition) { pArgRestrictBrkPtToThreadId->GetExpectedOption<CMICmdArgValNumber, MIuint>(m_nBrkPtThreadId); } // Determine if break on a file line or at a function BreakPoint_e eBrkPtType = eBreakPoint_NotDefineYet; CMIUtilString fileName; MIuint nFileLine = 0; CMIUtilString strFileFn; CMIUtilString rStrLineOrFn; // Is the string in the form 'file:func' or 'file:line'? // If so, find the position of the ':' separator. const size_t nPosColon = findFileSeparatorPos(m_brkName); if (nPosColon != std::string::npos) { // Extract file name and line number from it fileName = m_brkName.substr(0, nPosColon); rStrLineOrFn = m_brkName.substr(nPosColon + 1, m_brkName.size() - nPosColon - 1); if (rStrLineOrFn.empty()) eBrkPtType = eBreakPoint_ByName; else { MIint64 nValue = 0; if (rStrLineOrFn.ExtractNumber(nValue)) { nFileLine = static_cast<MIuint>(nValue); eBrkPtType = eBreakPoint_ByFileLine; } else { strFileFn = rStrLineOrFn; eBrkPtType = eBreakPoint_ByFileFn; } } } // Determine if break defined as an address lldb::addr_t nAddress = 0; if (eBrkPtType == eBreakPoint_NotDefineYet) { MIint64 nValue = 0; if (m_brkName.ExtractNumber(nValue)) { nAddress = static_cast<lldb::addr_t>(nValue); eBrkPtType = eBreakPoint_ByAddress; } } // Break defined as an function if (eBrkPtType == eBreakPoint_NotDefineYet) { eBrkPtType = eBreakPoint_ByName; } // Ask LLDB to create a breakpoint bool bOk = MIstatus::success; CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); lldb::SBTarget sbTarget = rSessionInfo.GetTarget(); switch (eBrkPtType) { case eBreakPoint_ByAddress: m_brkPt = sbTarget.BreakpointCreateByAddress(nAddress); break; case eBreakPoint_ByFileFn: { lldb::SBFileSpecList module; // search in all modules lldb::SBFileSpecList compUnit; compUnit.Append (lldb::SBFileSpec(fileName.c_str())); m_brkPt = sbTarget.BreakpointCreateByName(strFileFn.c_str(), module, compUnit); break; } case eBreakPoint_ByFileLine: m_brkPt = sbTarget.BreakpointCreateByLocation(fileName.c_str(), nFileLine); break; case eBreakPoint_ByName: m_brkPt = sbTarget.BreakpointCreateByName(m_brkName.c_str(), nullptr); break; case eBreakPoint_count: case eBreakPoint_NotDefineYet: case eBreakPoint_Invalid: bOk = MIstatus::failure; break; } if (bOk) { if (!m_bBrkPtIsPending && (m_brkPt.GetNumLocations() == 0)) { sbTarget.BreakpointDelete(m_brkPt.GetID()); SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_BRKPT_LOCATION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_brkName.c_str())); return MIstatus::failure; } m_brkPt.SetEnabled(m_bBrkPtEnabled); m_brkPt.SetIgnoreCount(m_nBrkPtIgnoreCount); if (m_bBrkPtCondition) m_brkPt.SetCondition(m_brkPtCondition.c_str()); if (m_bBrkPtThreadId) m_brkPt.SetThreadID(m_nBrkPtThreadId); } // CODETAG_LLDB_BREAKPOINT_CREATION // This is in the main thread // Record break point information to be by LLDB event handler function CMICmnLLDBDebugSessionInfo::SBrkPtInfo sBrkPtInfo; if (!rSessionInfo.GetBrkPtInfo(m_brkPt, sBrkPtInfo)) return MIstatus::failure; sBrkPtInfo.m_id = m_brkPt.GetID(); sBrkPtInfo.m_bDisp = m_bBrkPtIsTemp; sBrkPtInfo.m_bEnabled = m_bBrkPtEnabled; sBrkPtInfo.m_bHaveArgOptionThreadGrp = m_bHaveArgOptionThreadGrp; sBrkPtInfo.m_strOptThrdGrp = m_strArgOptionThreadGrp; sBrkPtInfo.m_nTimes = m_brkPt.GetHitCount(); sBrkPtInfo.m_strOrigLoc = m_brkName; sBrkPtInfo.m_nIgnore = m_nBrkPtIgnoreCount; sBrkPtInfo.m_bPending = m_bBrkPtIsPending; sBrkPtInfo.m_bCondition = m_bBrkPtCondition; sBrkPtInfo.m_strCondition = m_brkPtCondition; sBrkPtInfo.m_bBrkPtThreadId = m_bBrkPtThreadId; sBrkPtInfo.m_nBrkPtThreadId = m_nBrkPtThreadId; bOk = bOk && rSessionInfo.RecordBrkPtInfo(m_brkPt.GetID(), sBrkPtInfo); if (!bOk) { SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_BRKPT_INVALID), m_cmdData.strMiCmd.c_str(), m_brkName.c_str())); return MIstatus::failure; } // CODETAG_LLDB_BRKPT_ID_MAX if (m_brkPt.GetID() > (lldb::break_id_t)rSessionInfo.m_nBrkPointCntMax) { SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_BRKPT_CNT_EXCEEDED), m_cmdData.strMiCmd.c_str(), rSessionInfo.m_nBrkPointCntMax, m_brkName.c_str())); return MIstatus::failure; } return MIstatus::success; }
//++ ------------------------------------------------------------------------------------ // Details: The monitoring on new line data calls back to the visitor object registered // with *this stdin monitoring. The monitoring to stops when the visitor returns // true for bYesExit flag. Errors output to log file. // This function runs in the thread "MI stdin monitor". // Type: Method. // vrwbYesAlive - (W) False = yes exit stdin monitoring, true = continue monitor. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmnStreamStdin::MonitorStdin(bool &vrwbYesAlive) { if (m_bShowPrompt) { CMICmnStreamStdout &rStdoutMan = CMICmnStreamStdout::Instance(); rStdoutMan.WriteMIResponse(m_strPromptCurrent.c_str()); m_bRedrawPrompt = false; } // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM if (m_bKeyCtrlCHit) { CMIDriver &rMIDriver = CMIDriver::Instance(); rMIDriver.SetExitApplicationFlag(false); if (rMIDriver.GetExitApplicationFlag()) { vrwbYesAlive = false; return MIstatus::success; } // Reset - the MI Driver received SIGINT during a running debug programm session m_bKeyCtrlCHit = false; } #if MICONFIG_POLL_FOR_STD_IN bool bAvail = true; // Check if there is stdin available if (InputAvailable(bAvail)) { // Early exit when there is no input if (!bAvail) return MIstatus::success; } else { vrwbYesAlive = false; CMIDriver::Instance().SetExitApplicationFlag(true); return MIstatus::failure; } #endif // MICONFIG_POLL_FOR_STD_IN // Read a line from std input CMIUtilString stdinErrMsg; const MIchar *pText = ReadLine(stdinErrMsg); // Did something go wrong const bool bHaveError(!stdinErrMsg.empty()); if ((pText == nullptr) || bHaveError) { if (bHaveError) { CMICmnStreamStdout::Instance().Write(stdinErrMsg); } return MIstatus::failure; } // We have text so send it off to the visitor bool bOk = MIstatus::success; if (m_pVisitor != nullptr) { bool bYesExit = false; bOk = m_pVisitor->ReadLine(CMIUtilString(pText), bYesExit); m_bRedrawPrompt = true; vrwbYesAlive = !bYesExit; } return bOk; }
//++ ------------------------------------------------------------------------------------ // Details: Splits string into array of strings using delimiter. However the string is // also considered for text surrounded by quotes. Text with quotes including the // delimiter is treated as a whole. If multiple delimiter are found in sequence // then they are not added to the list of splits. // Type: Method. // Args: vData - (R) String data to be split up. // vDelimiter - (R) Delimiter char or text. // vwVecSplits - (W) Container of splits found in string data. // Return: MIuint - Number of splits found in the string data. // Throws: None. //-- MIuint CMIUtilString::SplitConsiderQuotes( const CMIUtilString & vDelimiter, VecString_t & vwVecSplits ) const { vwVecSplits.clear(); if( this->empty() || vDelimiter.empty() ) return 0; MIint nPos = find( vDelimiter ); if( nPos == (MIint) std::string::npos ) { vwVecSplits.push_back( *this ); return 1; } const MIint strLen( length() ); if( nPos == strLen ) { vwVecSplits.push_back( *this ); return 1; } // Look for more quotes bool bHaveQuotes = false; const MIchar cQuote = '"'; MIint nPosQ = find( cQuote ); MIint nPosQ2 = (MIint) std::string::npos; if( nPosQ != (MIint) std::string::npos ) { nPosQ2 = find( cQuote, nPosQ + 1 ); bHaveQuotes = (nPosQ2 != (MIint) std::string::npos); } MIuint nAdd1( 1 ); if( (nPos > 0) && (substr( 0, nPos ) != vDelimiter) ) { nPos = 0; nAdd1 = 0; } MIint nPos2 = find( vDelimiter, nPos + 1 ); while( nPos2 != (MIint) std::string::npos ) { if( !bHaveQuotes || (bHaveQuotes && ((nPos2 > nPosQ2) || (nPos2 < nPosQ))) ) { // Extract text or quoted text const MIuint len( nPos2 - nPos - nAdd1 ); const std::string strSection( substr( nPos + nAdd1, len ) ); if( strSection != vDelimiter ) vwVecSplits.push_back( strSection.c_str() ); nPos += len + 1; nPos2 = find( vDelimiter, nPos + 1 ); nAdd1 = 0; if( bHaveQuotes && (nPos2 > nPosQ2) ) { // Reset, look for more quotes bHaveQuotes = false; nPosQ = find( cQuote, nPos ); nPosQ2 = (MIint) std::string::npos; if( nPosQ != (MIint) std::string::npos ) { nPosQ2 = find( cQuote, nPosQ + 1 ); bHaveQuotes = (nPosQ2 != (MIint) std::string::npos); } } } else { // Skip passed text in quotes nPos2 = find( vDelimiter, nPosQ2 + 1 ); } } const std::string strSection( substr( nPos, strLen - nPos ) ); if( (strSection.length() != 0) && (strSection != vDelimiter) ) vwVecSplits.push_back( strSection.c_str() ); return vwVecSplits.size(); }