//===-- MICmdCmdTarget.cpp --------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // Overview: CMICmdCmdTargetSelect implementation. // Third Party Headers: #include "lldb/API/SBCommandInterpreter.h" #include "lldb/API/SBCommandReturnObject.h" #include "lldb/API/SBStream.h" // In-house headers: #include "MICmdArgValNumber.h" #include "MICmdArgValOptionLong.h" #include "MICmdArgValOptionShort.h" #include "MICmdArgValString.h" #include "MICmdCmdTarget.h" #include "MICmnLLDBDebugSessionInfo.h" #include "MICmnLLDBDebugger.h" #include "MICmnMIOutOfBandRecord.h" #include "MICmnMIResultRecord.h" #include "MICmnMIValueConst.h" //++ //------------------------------------------------------------------------------------ // Details: CMICmdCmdTargetSelect constructor. // Type: Method. // Args: None. // Return: None. // Throws: None. //-- CMICmdCmdTargetSelect::CMICmdCmdTargetSelect() : 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() {} //++ //------------------------------------------------------------------------------------ // 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() { m_setCmdArgs.Add(new CMICmdArgValString(m_constStrArgNamedType, true, true)); m_setCmdArgs.Add( new CMICmdArgValString(m_constStrArgNamedParameters, true, true)); return 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() { 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.GetTarget().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 char *pPlugin("gdb-remote"); lldb::SBError error; lldb::SBProcess process = rSessionInfo.GetTarget().ConnectRemote( rSessionInfo.GetListener(), strUrl.c_str(), pPlugin, error); // Verify that we have managed to connect successfully lldb::SBStream errMsg; error.GetDescription(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; } // Set the environment path if we were given one CMIUtilString strWkDir; if (rSessionInfo.SharedDataRetrieve( rSessionInfo.m_constStrSharedDataKeyWkDir, strWkDir)) { lldb::SBDebugger &rDbgr = rSessionInfo.GetDebugger(); 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( rSessionInfo.m_constStrSharedDataSolibPath, strSolibPath)) { lldb::SBDebugger &rDbgr = rSessionInfo.GetDebugger(); 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() { const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Connected); m_miResultRecord = miRecordResult; CMICmnLLDBDebugSessionInfo &rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance()); lldb::pid_t pid = rSessionInfo.GetProcess().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() { return new CMICmdCmdTargetSelect(); } //++ //------------------------------------------------------------------------------------ // Details: CMICmdCmdTargetAttach constructor. // Type: Method. // Args: None. // Return: None. // Throws: None. //-- CMICmdCmdTargetAttach::CMICmdCmdTargetAttach() : m_constStrArgPid("pid"), m_constStrArgNamedFile("n"), m_constStrArgWaitFor("waitfor") { // Command factory matches this name with that received from the stdin stream m_strMiCmd = "target-attach"; // Required by the CMICmdFactory when registering *this command m_pSelfCreatorFn = &CMICmdCmdTargetAttach::CreateSelf; } //++ //------------------------------------------------------------------------------------ // Details: CMICmdCmdTargetAttach destructor. // Type: Overrideable. // Args: None. // Return: None. // Throws: None. //-- CMICmdCmdTargetAttach::~CMICmdCmdTargetAttach() {} //++ //------------------------------------------------------------------------------------ // 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 CMICmdCmdTargetAttach::ParseArgs() { m_setCmdArgs.Add(new CMICmdArgValNumber(m_constStrArgPid, false, true)); m_setCmdArgs.Add( new CMICmdArgValOptionShort(m_constStrArgNamedFile, false, true, CMICmdArgValListBase::eArgValType_String, 1)); m_setCmdArgs.Add( new CMICmdArgValOptionLong(m_constStrArgWaitFor, false, true)); return 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-attach file // 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 CMICmdCmdTargetAttach::Execute() { CMICMDBASE_GETOPTION(pArgPid, Number, m_constStrArgPid); CMICMDBASE_GETOPTION(pArgFile, OptionShort, m_constStrArgNamedFile); CMICMDBASE_GETOPTION(pArgWaitFor, OptionLong, m_constStrArgWaitFor); CMICmnLLDBDebugSessionInfo &rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance()); // If the current target is invalid, create one lldb::SBTarget target = rSessionInfo.GetTarget(); if (!target.IsValid()) { target = rSessionInfo.GetDebugger().CreateTarget(NULL); if (!target.IsValid()) { SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_TARGET_CURRENT), m_cmdData.strMiCmd.c_str())); return MIstatus::failure; } } lldb::SBError error; lldb::SBListener listener; if (pArgPid->GetFound() && pArgPid->GetValid()) { lldb::pid_t pid; pid = pArgPid->GetValue(); target.AttachToProcessWithID(listener, pid, error); } else if (pArgFile->GetFound() && pArgFile->GetValid()) { bool bWaitFor = (pArgWaitFor->GetFound()); CMIUtilString file; pArgFile->GetExpectedOption(file); target.AttachToProcessWithName(listener, file.c_str(), bWaitFor, error); } else { SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_ATTACH_BAD_ARGS), m_cmdData.strMiCmd.c_str())); return MIstatus::failure; } lldb::SBStream errMsg; if (error.Fail()) { SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_ATTACH_FAILED), m_cmdData.strMiCmd.c_str(), errMsg.GetData())); 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 CMICmdCmdTargetAttach::Acknowledge() { const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done); m_miResultRecord = miRecordResult; CMICmnLLDBDebugSessionInfo &rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance()); lldb::pid_t pid = rSessionInfo.GetProcess().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 *CMICmdCmdTargetAttach::CreateSelf() { return new CMICmdCmdTargetAttach(); } //++ //------------------------------------------------------------------------------------ // Details: CMICmdCmdTargetDetach constructor. // Type: Method. // Args: None. // Return: None. // Throws: None. //-- CMICmdCmdTargetDetach::CMICmdCmdTargetDetach() { // Command factory matches this name with that received from the stdin stream m_strMiCmd = "target-detach"; // Required by the CMICmdFactory when registering *this command m_pSelfCreatorFn = &CMICmdCmdTargetDetach::CreateSelf; } //++ //------------------------------------------------------------------------------------ // Details: CMICmdCmdTargetDetach destructor. // Type: Overrideable. // Args: None. // Return: None. // Throws: None. //-- CMICmdCmdTargetDetach::~CMICmdCmdTargetDetach() {} //++ //------------------------------------------------------------------------------------ // 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 CMICmdCmdTargetDetach::ParseArgs() { 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. // Synopsis: -target-attach file // 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 CMICmdCmdTargetDetach::Execute() { CMICmnLLDBDebugSessionInfo &rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance()); lldb::SBProcess process = rSessionInfo.GetProcess(); if (!process.IsValid()) { SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PROCESS), m_cmdData.strMiCmd.c_str())); return MIstatus::failure; } process.Detach(); 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 CMICmdCmdTargetDetach::Acknowledge() { const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done); m_miResultRecord = miRecordResult; 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 *CMICmdCmdTargetDetach::CreateSelf() { return new CMICmdCmdTargetDetach(); }