1 //===-- MICmdCmdTarget.cpp --------------------------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 // Overview: CMICmdCmdTargetSelect implementation.
11
12 // Third Party Headers:
13 #include "lldb/API/SBStream.h"
14 #include "lldb/API/SBError.h"
15
16 // In-house headers:
17 #include "MICmdArgValNumber.h"
18 #include "MICmdArgValOptionLong.h"
19 #include "MICmdArgValOptionShort.h"
20 #include "MICmdArgValString.h"
21 #include "MICmdCmdTarget.h"
22 #include "MICmnLLDBDebugSessionInfo.h"
23 #include "MICmnLLDBDebugger.h"
24 #include "MICmnMIOutOfBandRecord.h"
25 #include "MICmnMIResultRecord.h"
26 #include "MICmnMIValueConst.h"
27
28 //++
29 //------------------------------------------------------------------------------------
30 // Details: CMICmdCmdTargetSelect constructor.
31 // Type: Method.
32 // Args: None.
33 // Return: None.
34 // Throws: None.
35 //--
CMICmdCmdTargetSelect()36 CMICmdCmdTargetSelect::CMICmdCmdTargetSelect()
37 : m_constStrArgNamedType("type"),
38 m_constStrArgNamedParameters("parameters") {
39 // Command factory matches this name with that received from the stdin stream
40 m_strMiCmd = "target-select";
41
42 // Required by the CMICmdFactory when registering *this command
43 m_pSelfCreatorFn = &CMICmdCmdTargetSelect::CreateSelf;
44 }
45
46 //++
47 //------------------------------------------------------------------------------------
48 // Details: CMICmdCmdTargetSelect destructor.
49 // Type: Overrideable.
50 // Args: None.
51 // Return: None.
52 // Throws: None.
53 //--
54 CMICmdCmdTargetSelect::~CMICmdCmdTargetSelect() = default;
55
56 //++
57 //------------------------------------------------------------------------------------
58 // Details: The invoker requires this function. The parses the command line
59 // options
60 // arguments to extract values for each of those arguments.
61 // Type: Overridden.
62 // Args: None.
63 // Return: MIstatus::success - Functional succeeded.
64 // MIstatus::failure - Functional failed.
65 // Throws: None.
66 //--
ParseArgs()67 bool CMICmdCmdTargetSelect::ParseArgs() {
68 m_setCmdArgs.Add(new CMICmdArgValString(m_constStrArgNamedType, true, true));
69 m_setCmdArgs.Add(
70 new CMICmdArgValString(m_constStrArgNamedParameters, true, true));
71 return ParseValidateCmdOptions();
72 }
73
74 //++
75 //------------------------------------------------------------------------------------
76 // Details: The invoker requires this function. The command does work in this
77 // function.
78 // The command is likely to communicate with the LLDB SBDebugger in
79 // here.
80 // Synopsis: -target-select type parameters ...
81 // Ref:
82 // http://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Target-Manipulation.html#GDB_002fMI-Target-Manipulation
83 // Type: Overridden.
84 // Args: None.
85 // Return: MIstatus::success - Functional succeeded.
86 // MIstatus::failure - Functional failed.
87 // Throws: None.
88 //--
Execute()89 bool CMICmdCmdTargetSelect::Execute() {
90 CMICMDBASE_GETOPTION(pArgType, String, m_constStrArgNamedType);
91 CMICMDBASE_GETOPTION(pArgParameters, String, m_constStrArgNamedParameters);
92
93 CMICmnLLDBDebugSessionInfo &rSessionInfo(
94 CMICmnLLDBDebugSessionInfo::Instance());
95 lldb::SBTarget target = rSessionInfo.GetTarget();
96
97 // Check we have a valid target.
98 // Note: target created via 'file-exec-and-symbols' command.
99 if (!target.IsValid()) {
100 SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_TARGET_CURRENT),
101 m_cmdData.strMiCmd.c_str()));
102 return MIstatus::failure;
103 }
104
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;
112 }
113
114 // Create a URL pointing to the remote gdb stub.
115 const CMIUtilString strUrl =
116 CMIUtilString::Format("connect://%s", pArgParameters->GetValue().c_str());
117
118 lldb::SBError error;
119 // Ask LLDB to connect to the target port.
120 const char *pPlugin("gdb-remote");
121 lldb::SBProcess process = target.ConnectRemote(
122 rSessionInfo.GetListener(), strUrl.c_str(), pPlugin, error);
123
124 // Verify that we have managed to connect successfully.
125 if (!process.IsValid()) {
126 SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_TARGET_PLUGIN),
127 m_cmdData.strMiCmd.c_str(),
128 error.GetCString()));
129 return MIstatus::failure;
130 }
131
132 // Set the environment path if we were given one.
133 CMIUtilString strWkDir;
134 if (rSessionInfo.SharedDataRetrieve<CMIUtilString>(
135 rSessionInfo.m_constStrSharedDataKeyWkDir, strWkDir)) {
136 lldb::SBDebugger &rDbgr = rSessionInfo.GetDebugger();
137 if (!rDbgr.SetCurrentPlatformSDKRoot(strWkDir.c_str())) {
138 SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_FNFAILED),
139 m_cmdData.strMiCmd.c_str(),
140 "target-select"));
141 return MIstatus::failure;
142 }
143 }
144
145 // Set the shared object path if we were given one.
146 CMIUtilString strSolibPath;
147 if (rSessionInfo.SharedDataRetrieve<CMIUtilString>(
148 rSessionInfo.m_constStrSharedDataSolibPath, strSolibPath))
149 target.AppendImageSearchPath(".", strSolibPath.c_str(), error);
150
151 return HandleSBError(error);
152 }
153
154 //++
155 //------------------------------------------------------------------------------------
156 // Details: The invoker requires this function. The command prepares a MI Record
157 // Result
158 // for the work carried out in the Execute().
159 // Type: Overridden.
160 // Args: None.
161 // Return: MIstatus::success - Functional succeeded.
162 // MIstatus::failure - Functional failed.
163 // Throws: None.
164 //--
Acknowledge()165 bool CMICmdCmdTargetSelect::Acknowledge() {
166 const CMICmnMIResultRecord miRecordResult(
167 m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Connected);
168 m_miResultRecord = miRecordResult;
169
170 CMICmnLLDBDebugSessionInfo &rSessionInfo(
171 CMICmnLLDBDebugSessionInfo::Instance());
172 lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID();
173 // Prod the client i.e. Eclipse with out-of-band results to help it 'continue'
174 // because it is using LLDB debugger
175 // Give the client '=thread-group-started,id="i1"'
176 m_bHasResultRecordExtra = true;
177 const CMICmnMIValueConst miValueConst2("i1");
178 const CMICmnMIValueResult miValueResult2("id", miValueConst2);
179 const CMIUtilString strPid(CMIUtilString::Format("%lld", pid));
180 const CMICmnMIValueConst miValueConst(strPid);
181 const CMICmnMIValueResult miValueResult("pid", miValueConst);
182 CMICmnMIOutOfBandRecord miOutOfBand(
183 CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupStarted, miValueResult2);
184 miOutOfBand.Add(miValueResult);
185 m_miResultRecordExtra = miOutOfBand.GetString();
186
187 return MIstatus::success;
188 }
189
190 //++
191 //------------------------------------------------------------------------------------
192 // Details: Required by the CMICmdFactory when registering *this command. The
193 // factory
194 // calls this function to create an instance of *this command.
195 // Type: Static method.
196 // Args: None.
197 // Return: CMICmdBase * - Pointer to a new command.
198 // Throws: None.
199 //--
CreateSelf()200 CMICmdBase *CMICmdCmdTargetSelect::CreateSelf() {
201 return new CMICmdCmdTargetSelect();
202 }
203
204 //++
205 //------------------------------------------------------------------------------------
206 // Details: CMICmdCmdTargetAttach constructor.
207 // Type: Method.
208 // Args: None.
209 // Return: None.
210 // Throws: None.
211 //--
CMICmdCmdTargetAttach()212 CMICmdCmdTargetAttach::CMICmdCmdTargetAttach()
213 : m_constStrArgPid("pid"), m_constStrArgNamedFile("n"),
214 m_constStrArgWaitFor("waitfor") {
215 // Command factory matches this name with that received from the stdin stream
216 m_strMiCmd = "target-attach";
217
218 // Required by the CMICmdFactory when registering *this command
219 m_pSelfCreatorFn = &CMICmdCmdTargetAttach::CreateSelf;
220 }
221
222 //++
223 //------------------------------------------------------------------------------------
224 // Details: CMICmdCmdTargetAttach destructor.
225 // Type: Overrideable.
226 // Args: None.
227 // Return: None.
228 // Throws: None.
229 //--
~CMICmdCmdTargetAttach()230 CMICmdCmdTargetAttach::~CMICmdCmdTargetAttach() {}
231
232 //++
233 //------------------------------------------------------------------------------------
234 // Details: The invoker requires this function. The parses the command line
235 // options
236 // arguments to extract values for each of those arguments.
237 // Type: Overridden.
238 // Args: None.
239 // Return: MIstatus::success - Functional succeeded.
240 // MIstatus::failure - Functional failed.
241 // Throws: None.
242 //--
ParseArgs()243 bool CMICmdCmdTargetAttach::ParseArgs() {
244 m_setCmdArgs.Add(new CMICmdArgValNumber(m_constStrArgPid, false, true));
245 m_setCmdArgs.Add(
246 new CMICmdArgValOptionShort(m_constStrArgNamedFile, false, true,
247 CMICmdArgValListBase::eArgValType_String, 1));
248 m_setCmdArgs.Add(
249 new CMICmdArgValOptionLong(m_constStrArgWaitFor, false, true));
250 return ParseValidateCmdOptions();
251 }
252
253 //++
254 //------------------------------------------------------------------------------------
255 // Details: The invoker requires this function. The command does work in this
256 // function.
257 // The command is likely to communicate with the LLDB SBDebugger in
258 // here.
259 // Synopsis: -target-attach file
260 // Ref:
261 // http://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Target-Manipulation.html#GDB_002fMI-Target-Manipulation
262 // Type: Overridden.
263 // Args: None.
264 // Return: MIstatus::success - Functional succeeded.
265 // MIstatus::failure - Functional failed.
266 // Throws: None.
267 //--
Execute()268 bool CMICmdCmdTargetAttach::Execute() {
269 CMICMDBASE_GETOPTION(pArgPid, Number, m_constStrArgPid);
270 CMICMDBASE_GETOPTION(pArgFile, OptionShort, m_constStrArgNamedFile);
271 CMICMDBASE_GETOPTION(pArgWaitFor, OptionLong, m_constStrArgWaitFor);
272
273 CMICmnLLDBDebugSessionInfo &rSessionInfo(
274 CMICmnLLDBDebugSessionInfo::Instance());
275
276 // If the current target is invalid, create one
277 lldb::SBTarget target = rSessionInfo.GetTarget();
278 if (!target.IsValid()) {
279 target = rSessionInfo.GetDebugger().CreateTarget(NULL);
280 if (!target.IsValid()) {
281 SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_TARGET_CURRENT),
282 m_cmdData.strMiCmd.c_str()));
283 return MIstatus::failure;
284 }
285 }
286
287 lldb::SBError error;
288 lldb::SBListener listener;
289 if (pArgPid->GetFound() && pArgPid->GetValid()) {
290 lldb::pid_t pid;
291 pid = pArgPid->GetValue();
292 target.AttachToProcessWithID(listener, pid, error);
293 } else if (pArgFile->GetFound() && pArgFile->GetValid()) {
294 bool bWaitFor = (pArgWaitFor->GetFound());
295 CMIUtilString file;
296 pArgFile->GetExpectedOption<CMICmdArgValString>(file);
297 target.AttachToProcessWithName(listener, file.c_str(), bWaitFor, error);
298 } else {
299 SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_ATTACH_BAD_ARGS),
300 m_cmdData.strMiCmd.c_str()));
301 return MIstatus::failure;
302 }
303
304 lldb::SBStream errMsg;
305 if (error.Fail()) {
306 SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_ATTACH_FAILED),
307 m_cmdData.strMiCmd.c_str(),
308 errMsg.GetData()));
309 return MIstatus::failure;
310 }
311
312 return MIstatus::success;
313 }
314
315 //++
316 //------------------------------------------------------------------------------------
317 // Details: The invoker requires this function. The command prepares a MI Record
318 // Result
319 // for the work carried out in the Execute().
320 // Type: Overridden.
321 // Args: None.
322 // Return: MIstatus::success - Functional succeeded.
323 // MIstatus::failure - Functional failed.
324 // Throws: None.
325 //--
Acknowledge()326 bool CMICmdCmdTargetAttach::Acknowledge() {
327 const CMICmnMIResultRecord miRecordResult(
328 m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done);
329 m_miResultRecord = miRecordResult;
330
331 CMICmnLLDBDebugSessionInfo &rSessionInfo(
332 CMICmnLLDBDebugSessionInfo::Instance());
333 lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID();
334 // Prod the client i.e. Eclipse with out-of-band results to help it 'continue'
335 // because it is using LLDB debugger
336 // Give the client '=thread-group-started,id="i1"'
337 m_bHasResultRecordExtra = true;
338 const CMICmnMIValueConst miValueConst2("i1");
339 const CMICmnMIValueResult miValueResult2("id", miValueConst2);
340 const CMIUtilString strPid(CMIUtilString::Format("%lld", pid));
341 const CMICmnMIValueConst miValueConst(strPid);
342 const CMICmnMIValueResult miValueResult("pid", miValueConst);
343 CMICmnMIOutOfBandRecord miOutOfBand(
344 CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupStarted, miValueResult2);
345 miOutOfBand.Add(miValueResult);
346 m_miResultRecordExtra = miOutOfBand.GetString();
347
348 return MIstatus::success;
349 }
350
351 //++
352 //------------------------------------------------------------------------------------
353 // Details: Required by the CMICmdFactory when registering *this command. The
354 // factory
355 // calls this function to create an instance of *this command.
356 // Type: Static method.
357 // Args: None.
358 // Return: CMICmdBase * - Pointer to a new command.
359 // Throws: None.
360 //--
CreateSelf()361 CMICmdBase *CMICmdCmdTargetAttach::CreateSelf() {
362 return new CMICmdCmdTargetAttach();
363 }
364
365 //++
366 //------------------------------------------------------------------------------------
367 // Details: CMICmdCmdTargetDetach constructor.
368 // Type: Method.
369 // Args: None.
370 // Return: None.
371 // Throws: None.
372 //--
CMICmdCmdTargetDetach()373 CMICmdCmdTargetDetach::CMICmdCmdTargetDetach() {
374 // Command factory matches this name with that received from the stdin stream
375 m_strMiCmd = "target-detach";
376
377 // Required by the CMICmdFactory when registering *this command
378 m_pSelfCreatorFn = &CMICmdCmdTargetDetach::CreateSelf;
379 }
380
381 //++
382 //------------------------------------------------------------------------------------
383 // Details: CMICmdCmdTargetDetach destructor.
384 // Type: Overrideable.
385 // Args: None.
386 // Return: None.
387 // Throws: None.
388 //--
~CMICmdCmdTargetDetach()389 CMICmdCmdTargetDetach::~CMICmdCmdTargetDetach() {}
390
391 //++
392 //------------------------------------------------------------------------------------
393 // Details: The invoker requires this function. The parses the command line
394 // options
395 // arguments to extract values for each of those arguments.
396 // Type: Overridden.
397 // Args: None.
398 // Return: MIstatus::success - Functional succeeded.
399 // MIstatus::failure - Functional failed.
400 // Throws: None.
401 //--
ParseArgs()402 bool CMICmdCmdTargetDetach::ParseArgs() { return MIstatus::success; }
403
404 //++
405 //------------------------------------------------------------------------------------
406 // Details: The invoker requires this function. The command does work in this
407 // function.
408 // The command is likely to communicate with the LLDB SBDebugger in
409 // here.
410 // Synopsis: -target-attach file
411 // Ref:
412 // http://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Target-Manipulation.html#GDB_002fMI-Target-Manipulation
413 // Type: Overridden.
414 // Args: None.
415 // Return: MIstatus::success - Functional succeeded.
416 // MIstatus::failure - Functional failed.
417 // Throws: None.
418 //--
Execute()419 bool CMICmdCmdTargetDetach::Execute() {
420 CMICmnLLDBDebugSessionInfo &rSessionInfo(
421 CMICmnLLDBDebugSessionInfo::Instance());
422
423 lldb::SBProcess process = rSessionInfo.GetProcess();
424
425 if (!process.IsValid()) {
426 SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PROCESS),
427 m_cmdData.strMiCmd.c_str()));
428 return MIstatus::failure;
429 }
430
431 process.Detach();
432
433 return MIstatus::success;
434 }
435
436 //++
437 //------------------------------------------------------------------------------------
438 // Details: The invoker requires this function. The command prepares a MI Record
439 // Result
440 // for the work carried out in the Execute().
441 // Type: Overridden.
442 // Args: None.
443 // Return: MIstatus::success - Functional succeeded.
444 // MIstatus::failure - Functional failed.
445 // Throws: None.
446 //--
Acknowledge()447 bool CMICmdCmdTargetDetach::Acknowledge() {
448 const CMICmnMIResultRecord miRecordResult(
449 m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done);
450 m_miResultRecord = miRecordResult;
451 return MIstatus::success;
452 }
453
454 //++
455 //------------------------------------------------------------------------------------
456 // Details: Required by the CMICmdFactory when registering *this command. The
457 // factory
458 // calls this function to create an instance of *this command.
459 // Type: Static method.
460 // Args: None.
461 // Return: CMICmdBase * - Pointer to a new command.
462 // Throws: None.
463 //--
CreateSelf()464 CMICmdBase *CMICmdCmdTargetDetach::CreateSelf() {
465 return new CMICmdCmdTargetDetach();
466 }
467