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