1 //===-- MICmdCmdTarget.cpp --------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // Overview: CMICmdCmdTargetSelect implementation.
12 // Third Party Headers:
13 #include "lldb/API/SBCommandInterpreter.h"
14 #include "lldb/API/SBCommandReturnObject.h"
15 #include "lldb/API/SBStream.h"
18 #include "MICmdArgValNumber.h"
19 #include "MICmdArgValOptionLong.h"
20 #include "MICmdArgValOptionShort.h"
21 #include "MICmdArgValString.h"
22 #include "MICmdCmdTarget.h"
23 #include "MICmnLLDBDebugSessionInfo.h"
24 #include "MICmnLLDBDebugger.h"
25 #include "MICmnMIOutOfBandRecord.h"
26 #include "MICmnMIResultRecord.h"
27 #include "MICmnMIValueConst.h"
30 //------------------------------------------------------------------------------------
31 // Details: CMICmdCmdTargetSelect constructor.
37 CMICmdCmdTargetSelect::CMICmdCmdTargetSelect()
38 : m_constStrArgNamedType("type"),
39 m_constStrArgNamedParameters("parameters") {
40 // Command factory matches this name with that received from the stdin stream
41 m_strMiCmd = "target-select";
43 // Required by the CMICmdFactory when registering *this command
44 m_pSelfCreatorFn = &CMICmdCmdTargetSelect::CreateSelf;
48 //------------------------------------------------------------------------------------
49 // Details: CMICmdCmdTargetSelect destructor.
50 // Type: Overrideable.
55 CMICmdCmdTargetSelect::~CMICmdCmdTargetSelect() {}
58 //------------------------------------------------------------------------------------
59 // Details: The invoker requires this function. The parses the command line
61 // arguments to extract values for each of those arguments.
64 // Return: MIstatus::success - Functional succeeded.
65 // MIstatus::failure - Functional failed.
68 bool CMICmdCmdTargetSelect::ParseArgs() {
69 m_setCmdArgs.Add(new CMICmdArgValString(m_constStrArgNamedType, true, true));
71 new CMICmdArgValString(m_constStrArgNamedParameters, true, true));
72 return ParseValidateCmdOptions();
76 //------------------------------------------------------------------------------------
77 // Details: The invoker requires this function. The command does work in this
79 // The command is likely to communicate with the LLDB SBDebugger in
81 // Synopsis: -target-select type parameters ...
83 // http://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Target-Manipulation.html#GDB_002fMI-Target-Manipulation
86 // Return: MIstatus::success - Functional succeeded.
87 // MIstatus::failure - Functional failed.
90 bool CMICmdCmdTargetSelect::Execute() {
91 CMICMDBASE_GETOPTION(pArgType, String, m_constStrArgNamedType);
92 CMICMDBASE_GETOPTION(pArgParameters, String, m_constStrArgNamedParameters);
94 CMICmnLLDBDebugSessionInfo &rSessionInfo(
95 CMICmnLLDBDebugSessionInfo::Instance());
97 // Check we have a valid target
98 // Note: target created via 'file-exec-and-symbols' command
99 if (!rSessionInfo.GetTarget().IsValid()) {
100 SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_TARGET_CURRENT),
101 m_cmdData.strMiCmd.c_str()));
102 return MIstatus::failure;
105 // Verify that we are executing remotely
106 const CMIUtilString &rRemoteType(pArgType->GetValue());
107 if (rRemoteType != "remote") {
108 SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_TARGET_TYPE),
109 m_cmdData.strMiCmd.c_str(),
110 rRemoteType.c_str()));
111 return MIstatus::failure;
114 // Create a URL pointing to the remote gdb stub
115 const CMIUtilString strUrl =
116 CMIUtilString::Format("connect://%s", pArgParameters->GetValue().c_str());
118 // Ask LLDB to connect to the target port
119 const char *pPlugin("gdb-remote");
121 lldb::SBProcess process = rSessionInfo.GetTarget().ConnectRemote(
122 rSessionInfo.GetListener(), strUrl.c_str(), pPlugin, error);
124 // Verify that we have managed to connect successfully
125 lldb::SBStream errMsg;
126 error.GetDescription(errMsg);
127 if (!process.IsValid()) {
128 SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_TARGET_PLUGIN),
129 m_cmdData.strMiCmd.c_str(),
131 return MIstatus::failure;
134 SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_CONNECT_TO_TARGET),
135 m_cmdData.strMiCmd.c_str(),
137 return MIstatus::failure;
140 // Set the environment path if we were given one
141 CMIUtilString strWkDir;
142 if (rSessionInfo.SharedDataRetrieve<CMIUtilString>(
143 rSessionInfo.m_constStrSharedDataKeyWkDir, strWkDir)) {
144 lldb::SBDebugger &rDbgr = rSessionInfo.GetDebugger();
145 if (!rDbgr.SetCurrentPlatformSDKRoot(strWkDir.c_str())) {
146 SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_FNFAILED),
147 m_cmdData.strMiCmd.c_str(),
149 return MIstatus::failure;
153 // Set the shared object path if we were given one
154 CMIUtilString strSolibPath;
155 if (rSessionInfo.SharedDataRetrieve<CMIUtilString>(
156 rSessionInfo.m_constStrSharedDataSolibPath, strSolibPath)) {
157 lldb::SBDebugger &rDbgr = rSessionInfo.GetDebugger();
158 lldb::SBCommandInterpreter cmdIterpreter = rDbgr.GetCommandInterpreter();
160 CMIUtilString strCmdString = CMIUtilString::Format(
161 "target modules search-paths add . %s", strSolibPath.c_str());
163 lldb::SBCommandReturnObject retObj;
164 cmdIterpreter.HandleCommand(strCmdString.c_str(), retObj, false);
166 if (!retObj.Succeeded()) {
167 SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_FNFAILED),
168 m_cmdData.strMiCmd.c_str(),
170 return MIstatus::failure;
174 return MIstatus::success;
178 //------------------------------------------------------------------------------------
179 // Details: The invoker requires this function. The command prepares a MI Record
181 // for the work carried out in the Execute().
184 // Return: MIstatus::success - Functional succeeded.
185 // MIstatus::failure - Functional failed.
188 bool CMICmdCmdTargetSelect::Acknowledge() {
189 const CMICmnMIResultRecord miRecordResult(
190 m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Connected);
191 m_miResultRecord = miRecordResult;
193 CMICmnLLDBDebugSessionInfo &rSessionInfo(
194 CMICmnLLDBDebugSessionInfo::Instance());
195 lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID();
196 // Prod the client i.e. Eclipse with out-of-band results to help it 'continue'
197 // because it is using LLDB debugger
198 // Give the client '=thread-group-started,id="i1"'
199 m_bHasResultRecordExtra = true;
200 const CMICmnMIValueConst miValueConst2("i1");
201 const CMICmnMIValueResult miValueResult2("id", miValueConst2);
202 const CMIUtilString strPid(CMIUtilString::Format("%lld", pid));
203 const CMICmnMIValueConst miValueConst(strPid);
204 const CMICmnMIValueResult miValueResult("pid", miValueConst);
205 CMICmnMIOutOfBandRecord miOutOfBand(
206 CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupStarted, miValueResult2);
207 miOutOfBand.Add(miValueResult);
208 m_miResultRecordExtra = miOutOfBand.GetString();
210 return MIstatus::success;
214 //------------------------------------------------------------------------------------
215 // Details: Required by the CMICmdFactory when registering *this command. The
217 // calls this function to create an instance of *this command.
218 // Type: Static method.
220 // Return: CMICmdBase * - Pointer to a new command.
223 CMICmdBase *CMICmdCmdTargetSelect::CreateSelf() {
224 return new CMICmdCmdTargetSelect();
228 //------------------------------------------------------------------------------------
229 // Details: CMICmdCmdTargetAttach constructor.
235 CMICmdCmdTargetAttach::CMICmdCmdTargetAttach()
236 : m_constStrArgPid("pid"), m_constStrArgNamedFile("n"),
237 m_constStrArgWaitFor("waitfor") {
238 // Command factory matches this name with that received from the stdin stream
239 m_strMiCmd = "target-attach";
241 // Required by the CMICmdFactory when registering *this command
242 m_pSelfCreatorFn = &CMICmdCmdTargetAttach::CreateSelf;
246 //------------------------------------------------------------------------------------
247 // Details: CMICmdCmdTargetAttach destructor.
248 // Type: Overrideable.
253 CMICmdCmdTargetAttach::~CMICmdCmdTargetAttach() {}
256 //------------------------------------------------------------------------------------
257 // Details: The invoker requires this function. The parses the command line
259 // arguments to extract values for each of those arguments.
262 // Return: MIstatus::success - Functional succeeded.
263 // MIstatus::failure - Functional failed.
266 bool CMICmdCmdTargetAttach::ParseArgs() {
267 m_setCmdArgs.Add(new CMICmdArgValNumber(m_constStrArgPid, false, true));
269 new CMICmdArgValOptionShort(m_constStrArgNamedFile, false, true,
270 CMICmdArgValListBase::eArgValType_String, 1));
272 new CMICmdArgValOptionLong(m_constStrArgWaitFor, false, true));
273 return ParseValidateCmdOptions();
277 //------------------------------------------------------------------------------------
278 // Details: The invoker requires this function. The command does work in this
280 // The command is likely to communicate with the LLDB SBDebugger in
282 // Synopsis: -target-attach file
284 // http://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Target-Manipulation.html#GDB_002fMI-Target-Manipulation
287 // Return: MIstatus::success - Functional succeeded.
288 // MIstatus::failure - Functional failed.
291 bool CMICmdCmdTargetAttach::Execute() {
292 CMICMDBASE_GETOPTION(pArgPid, Number, m_constStrArgPid);
293 CMICMDBASE_GETOPTION(pArgFile, OptionShort, m_constStrArgNamedFile);
294 CMICMDBASE_GETOPTION(pArgWaitFor, OptionLong, m_constStrArgWaitFor);
296 CMICmnLLDBDebugSessionInfo &rSessionInfo(
297 CMICmnLLDBDebugSessionInfo::Instance());
299 // If the current target is invalid, create one
300 lldb::SBTarget target = rSessionInfo.GetTarget();
301 if (!target.IsValid()) {
302 target = rSessionInfo.GetDebugger().CreateTarget(NULL);
303 if (!target.IsValid()) {
304 SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_TARGET_CURRENT),
305 m_cmdData.strMiCmd.c_str()));
306 return MIstatus::failure;
311 lldb::SBListener listener;
312 if (pArgPid->GetFound() && pArgPid->GetValid()) {
314 pid = pArgPid->GetValue();
315 target.AttachToProcessWithID(listener, pid, error);
316 } else if (pArgFile->GetFound() && pArgFile->GetValid()) {
317 bool bWaitFor = (pArgWaitFor->GetFound());
319 pArgFile->GetExpectedOption<CMICmdArgValString>(file);
320 target.AttachToProcessWithName(listener, file.c_str(), bWaitFor, error);
322 SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_ATTACH_BAD_ARGS),
323 m_cmdData.strMiCmd.c_str()));
324 return MIstatus::failure;
327 lldb::SBStream errMsg;
329 SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_ATTACH_FAILED),
330 m_cmdData.strMiCmd.c_str(),
332 return MIstatus::failure;
335 return MIstatus::success;
339 //------------------------------------------------------------------------------------
340 // Details: The invoker requires this function. The command prepares a MI Record
342 // for the work carried out in the Execute().
345 // Return: MIstatus::success - Functional succeeded.
346 // MIstatus::failure - Functional failed.
349 bool CMICmdCmdTargetAttach::Acknowledge() {
350 const CMICmnMIResultRecord miRecordResult(
351 m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done);
352 m_miResultRecord = miRecordResult;
354 CMICmnLLDBDebugSessionInfo &rSessionInfo(
355 CMICmnLLDBDebugSessionInfo::Instance());
356 lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID();
357 // Prod the client i.e. Eclipse with out-of-band results to help it 'continue'
358 // because it is using LLDB debugger
359 // Give the client '=thread-group-started,id="i1"'
360 m_bHasResultRecordExtra = true;
361 const CMICmnMIValueConst miValueConst2("i1");
362 const CMICmnMIValueResult miValueResult2("id", miValueConst2);
363 const CMIUtilString strPid(CMIUtilString::Format("%lld", pid));
364 const CMICmnMIValueConst miValueConst(strPid);
365 const CMICmnMIValueResult miValueResult("pid", miValueConst);
366 CMICmnMIOutOfBandRecord miOutOfBand(
367 CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupStarted, miValueResult2);
368 miOutOfBand.Add(miValueResult);
369 m_miResultRecordExtra = miOutOfBand.GetString();
371 return MIstatus::success;
375 //------------------------------------------------------------------------------------
376 // Details: Required by the CMICmdFactory when registering *this command. The
378 // calls this function to create an instance of *this command.
379 // Type: Static method.
381 // Return: CMICmdBase * - Pointer to a new command.
384 CMICmdBase *CMICmdCmdTargetAttach::CreateSelf() {
385 return new CMICmdCmdTargetAttach();
389 //------------------------------------------------------------------------------------
390 // Details: CMICmdCmdTargetDetach constructor.
396 CMICmdCmdTargetDetach::CMICmdCmdTargetDetach() {
397 // Command factory matches this name with that received from the stdin stream
398 m_strMiCmd = "target-detach";
400 // Required by the CMICmdFactory when registering *this command
401 m_pSelfCreatorFn = &CMICmdCmdTargetDetach::CreateSelf;
405 //------------------------------------------------------------------------------------
406 // Details: CMICmdCmdTargetDetach destructor.
407 // Type: Overrideable.
412 CMICmdCmdTargetDetach::~CMICmdCmdTargetDetach() {}
415 //------------------------------------------------------------------------------------
416 // Details: The invoker requires this function. The parses the command line
418 // arguments to extract values for each of those arguments.
421 // Return: MIstatus::success - Functional succeeded.
422 // MIstatus::failure - Functional failed.
425 bool CMICmdCmdTargetDetach::ParseArgs() { return MIstatus::success; }
428 //------------------------------------------------------------------------------------
429 // Details: The invoker requires this function. The command does work in this
431 // The command is likely to communicate with the LLDB SBDebugger in
433 // Synopsis: -target-attach file
435 // http://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Target-Manipulation.html#GDB_002fMI-Target-Manipulation
438 // Return: MIstatus::success - Functional succeeded.
439 // MIstatus::failure - Functional failed.
442 bool CMICmdCmdTargetDetach::Execute() {
443 CMICmnLLDBDebugSessionInfo &rSessionInfo(
444 CMICmnLLDBDebugSessionInfo::Instance());
446 lldb::SBProcess process = rSessionInfo.GetProcess();
448 if (!process.IsValid()) {
449 SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PROCESS),
450 m_cmdData.strMiCmd.c_str()));
451 return MIstatus::failure;
456 return MIstatus::success;
460 //------------------------------------------------------------------------------------
461 // Details: The invoker requires this function. The command prepares a MI Record
463 // for the work carried out in the Execute().
466 // Return: MIstatus::success - Functional succeeded.
467 // MIstatus::failure - Functional failed.
470 bool CMICmdCmdTargetDetach::Acknowledge() {
471 const CMICmnMIResultRecord miRecordResult(
472 m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done);
473 m_miResultRecord = miRecordResult;
474 return MIstatus::success;
478 //------------------------------------------------------------------------------------
479 // Details: Required by the CMICmdFactory when registering *this command. The
481 // calls this function to create an instance of *this command.
482 // Type: Static method.
484 // Return: CMICmdBase * - Pointer to a new command.
487 CMICmdBase *CMICmdCmdTargetDetach::CreateSelf() {
488 return new CMICmdCmdTargetDetach();