//===-- MICmdCmdTarget.cpp --------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// //++ // File: MICmdCmdTarget.cpp // // Overview: CMICmdCmdTargetSelect implementation. // // Environment: Compilers: Visual C++ 12. // gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 // Libraries: See MIReadmetxt. // // Copyright: None. //-- // Third Party Headers: #include #include #include // In-house headers: #include "MICmdCmdTarget.h" #include "MICmnMIResultRecord.h" #include "MICmnMIValueConst.h" #include "MICmnMIOutOfBandRecord.h" #include "MICmnLLDBDebugger.h" #include "MICmnLLDBDebugSessionInfo.h" #include "MICmdArgValString.h" //++ ------------------------------------------------------------------------------------ // Details: CMICmdCmdTargetSelect constructor. // Type: Method. // Args: None. // Return: None. // Throws: None. //-- CMICmdCmdTargetSelect::CMICmdCmdTargetSelect( void ) : m_constStrArgNamedType( "type" ) , m_constStrArgNamedParameters( "parameters" ) { // Command factory matches this name with that received from the stdin stream m_strMiCmd = "target-select"; // Required by the CMICmdFactory when registering *this command m_pSelfCreatorFn = &CMICmdCmdTargetSelect::CreateSelf; } //++ ------------------------------------------------------------------------------------ // Details: CMICmdCmdTargetSelect destructor. // Type: Overrideable. // Args: None. // Return: None. // Throws: None. //-- CMICmdCmdTargetSelect::~CMICmdCmdTargetSelect( void ) { } //++ ------------------------------------------------------------------------------------ // Details: The invoker requires this function. The parses the command line options // arguments to extract values for each of those arguments. // Type: Overridden. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmdCmdTargetSelect::ParseArgs( void ) { bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgNamedType, true, true )) ); bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgNamedParameters, true, true )) ); return (bOk && ParseValidateCmdOptions() ); } //++ ------------------------------------------------------------------------------------ // 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. // Synopsis: -target-select type parameters ... // Ref: http://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Target-Manipulation.html#GDB_002fMI-Target-Manipulation // Type: Overridden. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmdCmdTargetSelect::Execute( void ) { CMICMDBASE_GETOPTION( pArgType, String, m_constStrArgNamedType ); CMICMDBASE_GETOPTION( pArgParameters, String, m_constStrArgNamedParameters ); CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() ); // Check we have a valid target // Note: target created via 'file-exec-and-symbols' command if( !rSessionInfo.m_lldbTarget.IsValid() ) { SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_INVALID_TARGET_CURRENT ), m_cmdData.strMiCmd.c_str() ) ); return MIstatus::failure; } // Verify that we are executing remotely const CMIUtilString & rRemoteType( pArgType->GetValue() ); if( rRemoteType != "remote" ) { SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_INVALID_TARGET_TYPE ), m_cmdData.strMiCmd.c_str(), rRemoteType.c_str() ) ); return MIstatus::failure; } // Create a URL pointing to the remote gdb stub const CMIUtilString strUrl = CMIUtilString::Format( "connect://%s", pArgParameters->GetValue().c_str() ); // Ask LLDB to collect to the target port const MIchar * pPlugin( "gdb-remote" ); lldb::SBError error; lldb::SBProcess process = rSessionInfo.m_lldbTarget.ConnectRemote( rSessionInfo.m_rLlldbListener, strUrl.c_str(), pPlugin, error ); // Verify that we have managed to connect successfully lldb::SBStream errMsg; if( !process.IsValid() ) { SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_INVALID_TARGET_PLUGIN ), m_cmdData.strMiCmd.c_str(), errMsg.GetData() ) ); return MIstatus::failure; } if( error.Fail() ) { SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_CONNECT_TO_TARGET ), m_cmdData.strMiCmd.c_str(), errMsg.GetData() ) ); return MIstatus::failure; } // Save the process in the session info // Note: Order is important here since this process handle may be used by CMICmnLLDBDebugHandleEvents // which can fire when interpreting via HandleCommand() below. rSessionInfo.m_lldbProcess = process; // Set the environment path if we were given one CMIUtilString strWkDir; if( rSessionInfo.SharedDataRetrieve< CMIUtilString >( rSessionInfo.m_constStrSharedDataKeyWkDir, strWkDir ) ) { lldb::SBDebugger & rDbgr = rSessionInfo.m_rLldbDebugger; if( !rDbgr.SetCurrentPlatformSDKRoot( strWkDir.c_str() ) ) { SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_FNFAILED ), m_cmdData.strMiCmd.c_str(), "target-select" ) ); return MIstatus::failure; } } // Set the shared object path if we were given one CMIUtilString strSolibPath; if( rSessionInfo.SharedDataRetrieve< CMIUtilString >( rSessionInfo.m_constStrSharedDataSolibPath, strSolibPath ) ) { lldb::SBDebugger & rDbgr = rSessionInfo.m_rLldbDebugger; lldb::SBCommandInterpreter cmdIterpreter = rDbgr.GetCommandInterpreter(); CMIUtilString strCmdString = CMIUtilString::Format( "target modules search-paths add . %s", strSolibPath.c_str() ); lldb::SBCommandReturnObject retObj; cmdIterpreter.HandleCommand( strCmdString.c_str(), retObj, false ); if( !retObj.Succeeded() ) { SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_FNFAILED ), m_cmdData.strMiCmd.c_str(), "target-select" ) ); return MIstatus::failure; } } return MIstatus::success; } //++ ------------------------------------------------------------------------------------ // Details: The invoker requires this function. The command prepares a MI Record Result // for the work carried out in the Execute(). // Type: Overridden. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmdCmdTargetSelect::Acknowledge( void ) { const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Connected ); m_miResultRecord = miRecordResult; CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() ); lldb::pid_t pid = rSessionInfo.m_lldbProcess.GetProcessID(); // Prod the client i.e. Eclipse with out-of-band results to help it 'continue' because it is using LLDB debugger // Give the client '=thread-group-started,id="i1"' m_bHasResultRecordExtra = true; const CMICmnMIValueConst miValueConst2( "i1" ); const CMICmnMIValueResult miValueResult2( "id", miValueConst2 ); const CMIUtilString strPid( CMIUtilString::Format( "%lld", pid ) ); const CMICmnMIValueConst miValueConst( strPid ); const CMICmnMIValueResult miValueResult( "pid", miValueConst ); CMICmnMIOutOfBandRecord miOutOfBand( CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupStarted, miValueResult2 ); miOutOfBand.Add( miValueResult ); m_miResultRecordExtra = miOutOfBand.GetString(); return MIstatus::success; } //++ ------------------------------------------------------------------------------------ // Details: Required by the CMICmdFactory when registering *this command. The factory // calls this function to create an instance of *this command. // Type: Static method. // Args: None. // Return: CMICmdBase * - Pointer to a new command. // Throws: None. //-- CMICmdBase * CMICmdCmdTargetSelect::CreateSelf( void ) { return new CMICmdCmdTargetSelect(); }