1 //===-- MICmdCmdTarget.cpp --------------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // Overview: CMICmdCmdTargetSelect implementation.
11 // Third Party Headers:
12 #include "lldb/API/SBStream.h"
13 #include "lldb/API/SBError.h"
16 #include "MICmdArgValNumber.h"
17 #include "MICmdArgValOptionLong.h"
18 #include "MICmdArgValOptionShort.h"
19 #include "MICmdArgValString.h"
20 #include "MICmdCmdTarget.h"
21 #include "MICmnLLDBDebugSessionInfo.h"
22 #include "MICmnLLDBDebugger.h"
23 #include "MICmnMIOutOfBandRecord.h"
24 #include "MICmnMIResultRecord.h"
25 #include "MICmnMIValueConst.h"
28 // Details: CMICmdCmdTargetSelect constructor.
34 CMICmdCmdTargetSelect::CMICmdCmdTargetSelect()
35 : m_constStrArgNamedType("type"),
36 m_constStrArgNamedParameters("parameters") {
37 // Command factory matches this name with that received from the stdin stream
38 m_strMiCmd = "target-select";
40 // Required by the CMICmdFactory when registering *this command
41 m_pSelfCreatorFn = &CMICmdCmdTargetSelect::CreateSelf;
45 // Details: CMICmdCmdTargetSelect destructor.
46 // Type: Overrideable.
51 CMICmdCmdTargetSelect::~CMICmdCmdTargetSelect() = default;
54 // Details: The invoker requires this function. The parses the command line
56 // arguments to extract values for each of those arguments.
59 // Return: MIstatus::success - Functional succeeded.
60 // MIstatus::failure - Functional failed.
63 bool CMICmdCmdTargetSelect::ParseArgs() {
64 m_setCmdArgs.Add(new CMICmdArgValString(m_constStrArgNamedType, true, true));
66 new CMICmdArgValString(m_constStrArgNamedParameters, true, true));
67 return ParseValidateCmdOptions();
71 // Details: The invoker requires this function. The command does work in this
73 // The command is likely to communicate with the LLDB SBDebugger in
75 // Synopsis: -target-select type parameters ...
77 // http://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Target-Manipulation.html#GDB_002fMI-Target-Manipulation
80 // Return: MIstatus::success - Functional succeeded.
81 // MIstatus::failure - Functional failed.
84 bool CMICmdCmdTargetSelect::Execute() {
85 CMICMDBASE_GETOPTION(pArgType, String, m_constStrArgNamedType);
86 CMICMDBASE_GETOPTION(pArgParameters, String, m_constStrArgNamedParameters);
88 CMICmnLLDBDebugSessionInfo &rSessionInfo(
89 CMICmnLLDBDebugSessionInfo::Instance());
90 lldb::SBTarget target = rSessionInfo.GetTarget();
92 // Check we have a valid target.
93 // Note: target created via 'file-exec-and-symbols' command.
94 if (!target.IsValid()) {
95 SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_TARGET_CURRENT),
96 m_cmdData.strMiCmd.c_str()));
97 return MIstatus::failure;
100 // Verify that we are executing remotely.
101 const CMIUtilString &rRemoteType(pArgType->GetValue());
102 if (rRemoteType != "remote") {
103 SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_TARGET_TYPE),
104 m_cmdData.strMiCmd.c_str(),
105 rRemoteType.c_str()));
106 return MIstatus::failure;
109 // Create a URL pointing to the remote gdb stub.
110 const CMIUtilString strUrl =
111 CMIUtilString::Format("connect://%s", pArgParameters->GetValue().c_str());
114 // Ask LLDB to connect to the target port.
115 const char *pPlugin("gdb-remote");
116 lldb::SBProcess process = target.ConnectRemote(
117 rSessionInfo.GetListener(), strUrl.c_str(), pPlugin, error);
119 // Verify that we have managed to connect successfully.
120 if (!process.IsValid()) {
121 SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_TARGET_PLUGIN),
122 m_cmdData.strMiCmd.c_str(),
123 error.GetCString()));
124 return MIstatus::failure;
127 // Set the environment path if we were given one.
128 CMIUtilString strWkDir;
129 if (rSessionInfo.SharedDataRetrieve<CMIUtilString>(
130 rSessionInfo.m_constStrSharedDataKeyWkDir, strWkDir)) {
131 lldb::SBDebugger &rDbgr = rSessionInfo.GetDebugger();
132 if (!rDbgr.SetCurrentPlatformSDKRoot(strWkDir.c_str())) {
133 SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_FNFAILED),
134 m_cmdData.strMiCmd.c_str(),
136 return MIstatus::failure;
140 // Set the shared object path if we were given one.
141 CMIUtilString strSolibPath;
142 if (rSessionInfo.SharedDataRetrieve<CMIUtilString>(
143 rSessionInfo.m_constStrSharedDataSolibPath, strSolibPath))
144 target.AppendImageSearchPath(".", strSolibPath.c_str(), error);
146 return HandleSBError(error);
150 // Details: The invoker requires this function. The command prepares a MI Record
152 // for the work carried out in the Execute().
155 // Return: MIstatus::success - Functional succeeded.
156 // MIstatus::failure - Functional failed.
159 bool CMICmdCmdTargetSelect::Acknowledge() {
160 const CMICmnMIResultRecord miRecordResult(
161 m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Connected);
162 m_miResultRecord = miRecordResult;
164 CMICmnLLDBDebugSessionInfo &rSessionInfo(
165 CMICmnLLDBDebugSessionInfo::Instance());
166 lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID();
167 // Prod the client i.e. Eclipse with out-of-band results to help it 'continue'
168 // because it is using LLDB debugger
169 // Give the client '=thread-group-started,id="i1"'
170 m_bHasResultRecordExtra = true;
171 const CMICmnMIValueConst miValueConst2("i1");
172 const CMICmnMIValueResult miValueResult2("id", miValueConst2);
173 const CMIUtilString strPid(CMIUtilString::Format("%lld", pid));
174 const CMICmnMIValueConst miValueConst(strPid);
175 const CMICmnMIValueResult miValueResult("pid", miValueConst);
176 CMICmnMIOutOfBandRecord miOutOfBand(
177 CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupStarted, miValueResult2);
178 miOutOfBand.Add(miValueResult);
179 m_miResultRecordExtra = miOutOfBand.GetString();
181 return MIstatus::success;
185 // Details: Required by the CMICmdFactory when registering *this command. The
187 // calls this function to create an instance of *this command.
188 // Type: Static method.
190 // Return: CMICmdBase * - Pointer to a new command.
193 CMICmdBase *CMICmdCmdTargetSelect::CreateSelf() {
194 return new CMICmdCmdTargetSelect();
198 // Details: CMICmdCmdTargetAttach constructor.
204 CMICmdCmdTargetAttach::CMICmdCmdTargetAttach()
205 : m_constStrArgPid("pid"), m_constStrArgNamedFile("n"),
206 m_constStrArgWaitFor("waitfor") {
207 // Command factory matches this name with that received from the stdin stream
208 m_strMiCmd = "target-attach";
210 // Required by the CMICmdFactory when registering *this command
211 m_pSelfCreatorFn = &CMICmdCmdTargetAttach::CreateSelf;
215 // Details: CMICmdCmdTargetAttach destructor.
216 // Type: Overrideable.
221 CMICmdCmdTargetAttach::~CMICmdCmdTargetAttach() {}
224 // Details: The invoker requires this function. The parses the command line
226 // arguments to extract values for each of those arguments.
229 // Return: MIstatus::success - Functional succeeded.
230 // MIstatus::failure - Functional failed.
233 bool CMICmdCmdTargetAttach::ParseArgs() {
234 m_setCmdArgs.Add(new CMICmdArgValNumber(m_constStrArgPid, false, true));
236 new CMICmdArgValOptionShort(m_constStrArgNamedFile, false, true,
237 CMICmdArgValListBase::eArgValType_String, 1));
239 new CMICmdArgValOptionLong(m_constStrArgWaitFor, false, true));
240 return ParseValidateCmdOptions();
244 // Details: The invoker requires this function. The command does work in this
246 // The command is likely to communicate with the LLDB SBDebugger in
248 // Synopsis: -target-attach file
250 // http://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Target-Manipulation.html#GDB_002fMI-Target-Manipulation
253 // Return: MIstatus::success - Functional succeeded.
254 // MIstatus::failure - Functional failed.
257 bool CMICmdCmdTargetAttach::Execute() {
258 CMICMDBASE_GETOPTION(pArgPid, Number, m_constStrArgPid);
259 CMICMDBASE_GETOPTION(pArgFile, OptionShort, m_constStrArgNamedFile);
260 CMICMDBASE_GETOPTION(pArgWaitFor, OptionLong, m_constStrArgWaitFor);
262 CMICmnLLDBDebugSessionInfo &rSessionInfo(
263 CMICmnLLDBDebugSessionInfo::Instance());
265 // If the current target is invalid, create one
266 lldb::SBTarget target = rSessionInfo.GetTarget();
267 if (!target.IsValid()) {
268 target = rSessionInfo.GetDebugger().CreateTarget(nullptr);
269 if (!target.IsValid()) {
270 SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_TARGET_CURRENT),
271 m_cmdData.strMiCmd.c_str()));
272 return MIstatus::failure;
277 lldb::SBListener listener;
278 if (pArgPid->GetFound() && pArgPid->GetValid()) {
280 pid = pArgPid->GetValue();
281 target.AttachToProcessWithID(listener, pid, error);
282 } else if (pArgFile->GetFound() && pArgFile->GetValid()) {
283 bool bWaitFor = (pArgWaitFor->GetFound());
285 pArgFile->GetExpectedOption<CMICmdArgValString>(file);
286 target.AttachToProcessWithName(listener, file.c_str(), bWaitFor, error);
288 SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_ATTACH_BAD_ARGS),
289 m_cmdData.strMiCmd.c_str()));
290 return MIstatus::failure;
293 lldb::SBStream errMsg;
295 SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_ATTACH_FAILED),
296 m_cmdData.strMiCmd.c_str(),
298 return MIstatus::failure;
301 return MIstatus::success;
305 // Details: The invoker requires this function. The command prepares a MI Record
307 // for the work carried out in the Execute().
310 // Return: MIstatus::success - Functional succeeded.
311 // MIstatus::failure - Functional failed.
314 bool CMICmdCmdTargetAttach::Acknowledge() {
315 const CMICmnMIResultRecord miRecordResult(
316 m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done);
317 m_miResultRecord = miRecordResult;
319 CMICmnLLDBDebugSessionInfo &rSessionInfo(
320 CMICmnLLDBDebugSessionInfo::Instance());
321 lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID();
322 // Prod the client i.e. Eclipse with out-of-band results to help it 'continue'
323 // because it is using LLDB debugger
324 // Give the client '=thread-group-started,id="i1"'
325 m_bHasResultRecordExtra = true;
326 const CMICmnMIValueConst miValueConst2("i1");
327 const CMICmnMIValueResult miValueResult2("id", miValueConst2);
328 const CMIUtilString strPid(CMIUtilString::Format("%lld", pid));
329 const CMICmnMIValueConst miValueConst(strPid);
330 const CMICmnMIValueResult miValueResult("pid", miValueConst);
331 CMICmnMIOutOfBandRecord miOutOfBand(
332 CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupStarted, miValueResult2);
333 miOutOfBand.Add(miValueResult);
334 m_miResultRecordExtra = miOutOfBand.GetString();
336 return MIstatus::success;
340 // Details: Required by the CMICmdFactory when registering *this command. The
342 // calls this function to create an instance of *this command.
343 // Type: Static method.
345 // Return: CMICmdBase * - Pointer to a new command.
348 CMICmdBase *CMICmdCmdTargetAttach::CreateSelf() {
349 return new CMICmdCmdTargetAttach();
353 // Details: CMICmdCmdTargetDetach constructor.
359 CMICmdCmdTargetDetach::CMICmdCmdTargetDetach() {
360 // Command factory matches this name with that received from the stdin stream
361 m_strMiCmd = "target-detach";
363 // Required by the CMICmdFactory when registering *this command
364 m_pSelfCreatorFn = &CMICmdCmdTargetDetach::CreateSelf;
368 // Details: CMICmdCmdTargetDetach destructor.
369 // Type: Overrideable.
374 CMICmdCmdTargetDetach::~CMICmdCmdTargetDetach() {}
377 // Details: The invoker requires this function. The parses the command line
379 // arguments to extract values for each of those arguments.
382 // Return: MIstatus::success - Functional succeeded.
383 // MIstatus::failure - Functional failed.
386 bool CMICmdCmdTargetDetach::ParseArgs() { return MIstatus::success; }
389 // Details: The invoker requires this function. The command does work in this
391 // The command is likely to communicate with the LLDB SBDebugger in
393 // Synopsis: -target-attach file
395 // http://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Target-Manipulation.html#GDB_002fMI-Target-Manipulation
398 // Return: MIstatus::success - Functional succeeded.
399 // MIstatus::failure - Functional failed.
402 bool CMICmdCmdTargetDetach::Execute() {
403 CMICmnLLDBDebugSessionInfo &rSessionInfo(
404 CMICmnLLDBDebugSessionInfo::Instance());
406 lldb::SBProcess process = rSessionInfo.GetProcess();
408 if (!process.IsValid()) {
409 SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PROCESS),
410 m_cmdData.strMiCmd.c_str()));
411 return MIstatus::failure;
416 return MIstatus::success;
420 // Details: The invoker requires this function. The command prepares a MI Record
422 // for the work carried out in the Execute().
425 // Return: MIstatus::success - Functional succeeded.
426 // MIstatus::failure - Functional failed.
429 bool CMICmdCmdTargetDetach::Acknowledge() {
430 const CMICmnMIResultRecord miRecordResult(
431 m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done);
432 m_miResultRecord = miRecordResult;
433 return MIstatus::success;
437 // Details: Required by the CMICmdFactory when registering *this command. The
439 // calls this function to create an instance of *this command.
440 // Type: Static method.
442 // Return: CMICmdBase * - Pointer to a new command.
445 CMICmdBase *CMICmdCmdTargetDetach::CreateSelf() {
446 return new CMICmdCmdTargetDetach();