1 //===-- MICmdCmdMiscellanous.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: CMICmdCmdGdbExit implementation.
10 // CMICmdCmdListThreadGroups implementation.
11 // CMICmdCmdInterpreterExec implementation.
12 // CMICmdCmdInferiorTtySet implementation.
14 // Third Party Headers:
15 #include "lldb/API/SBCommandInterpreter.h"
16 #include "lldb/API/SBThread.h"
19 #include "MICmdArgValFile.h"
20 #include "MICmdArgValListOfN.h"
21 #include "MICmdArgValNumber.h"
22 #include "MICmdArgValOptionLong.h"
23 #include "MICmdArgValOptionShort.h"
24 #include "MICmdArgValString.h"
25 #include "MICmdArgValThreadGrp.h"
26 #include "MICmdCmdMiscellanous.h"
27 #include "MICmnLLDBDebugSessionInfo.h"
28 #include "MICmnLLDBDebugger.h"
29 #include "MICmnMIOutOfBandRecord.h"
30 #include "MICmnMIResultRecord.h"
31 #include "MICmnMIValueConst.h"
32 #include "MICmnStreamStderr.h"
33 #include "MICmnStreamStdout.h"
34 #include "MIDriverBase.h"
37 // Details: CMICmdCmdGdbExit constructor.
43 CMICmdCmdGdbExit::CMICmdCmdGdbExit() {
44 // Command factory matches this name with that received from the stdin stream
45 m_strMiCmd = "gdb-exit";
47 // Required by the CMICmdFactory when registering *this command
48 m_pSelfCreatorFn = &CMICmdCmdGdbExit::CreateSelf;
52 // Details: CMICmdCmdGdbExit destructor.
53 // Type: Overrideable.
58 CMICmdCmdGdbExit::~CMICmdCmdGdbExit() {}
61 // Details: The invoker requires this function. The command does work in this
63 // The command is likely to communicate with the LLDB SBDebugger in
67 // Return: MIstatus::success - Functional succeeded.
68 // MIstatus::failure - Functional failed.
71 bool CMICmdCmdGdbExit::Execute() {
72 CMICmnLLDBDebugger::Instance().GetDriver().SetExitApplicationFlag(true);
73 const lldb::SBError sbErr = m_rLLDBDebugSessionInfo.GetProcess().Destroy();
74 // Do not check for sbErr.Fail() here, m_lldbProcess is likely !IsValid()
76 return MIstatus::success;
80 // Details: The invoker requires this function. The command prepares a MI Record
82 // for the work carried out in the Execute().
85 // Return: MIstatus::success - Functional succeeded.
86 // MIstatus::failure - Functional failed.
89 bool CMICmdCmdGdbExit::Acknowledge() {
90 const CMICmnMIResultRecord miRecordResult(
91 m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Exit);
92 m_miResultRecord = miRecordResult;
94 // Prod the client i.e. Eclipse with out-of-band results to help it 'continue'
95 // because it is using LLDB debugger
96 // Give the client '=thread-group-exited,id="i1"'
97 m_bHasResultRecordExtra = true;
98 const CMICmnMIValueConst miValueConst2("i1");
99 const CMICmnMIValueResult miValueResult2("id", miValueConst2);
100 const CMICmnMIOutOfBandRecord miOutOfBand(
101 CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupExited, miValueResult2);
102 m_miResultRecordExtra = miOutOfBand.GetString();
104 return MIstatus::success;
108 // Details: Required by the CMICmdFactory when registering *this command. The
110 // calls this function to create an instance of *this command.
111 // Type: Static method.
113 // Return: CMICmdBase * - Pointer to a new command.
116 CMICmdBase *CMICmdCmdGdbExit::CreateSelf() { return new CMICmdCmdGdbExit(); }
120 // Details: CMICmdCmdListThreadGroups constructor.
126 CMICmdCmdListThreadGroups::CMICmdCmdListThreadGroups()
127 : m_bIsI1(false), m_bHaveArgOption(false), m_bHaveArgRecurse(false),
128 m_constStrArgNamedAvailable("available"),
129 m_constStrArgNamedRecurse("recurse"), m_constStrArgNamedGroup("group"),
130 m_constStrArgNamedThreadGroup("i1") {
131 // Command factory matches this name with that received from the stdin stream
132 m_strMiCmd = "list-thread-groups";
134 // Required by the CMICmdFactory when registering *this command
135 m_pSelfCreatorFn = &CMICmdCmdListThreadGroups::CreateSelf;
139 // Details: CMICmdCmdListThreadGroups destructor.
140 // Type: Overrideable.
145 CMICmdCmdListThreadGroups::~CMICmdCmdListThreadGroups() {
146 m_vecMIValueTuple.clear();
150 // Details: The invoker requires this function. The parses the command line
152 // arguments to extract values for each of those arguments.
155 // Return: MIstatus::success - Functional succeeded.
156 // MIstatus::failure - Functional failed.
159 bool CMICmdCmdListThreadGroups::ParseArgs() {
161 new CMICmdArgValOptionLong(m_constStrArgNamedAvailable, false, true));
163 new CMICmdArgValOptionLong(m_constStrArgNamedRecurse, false, true,
164 CMICmdArgValListBase::eArgValType_Number, 1));
166 new CMICmdArgValListOfN(m_constStrArgNamedGroup, false, true,
167 CMICmdArgValListBase::eArgValType_Number));
169 new CMICmdArgValThreadGrp(m_constStrArgNamedThreadGroup, false, true));
170 return ParseValidateCmdOptions();
174 // Details: The invoker requires this function. The command does work in this
176 // The command is likely to communicate with the LLDB SBDebugger in
178 // Synopsis: -list-thread-groups [ --available ] [ --recurse 1 ] [
180 // This command does not follow the MI documentation exactly. Has an
182 // argument "i1" to handle.
184 // http://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Miscellaneous-Commands.html#GDB_002fMI-Miscellaneous-Commands
187 // Return: MIstatus::success - Functional succeeded.
188 // MIstatus::failure - Functional failed.
191 bool CMICmdCmdListThreadGroups::Execute() {
192 if (m_setCmdArgs.IsArgContextEmpty())
193 // No options so "top level thread groups"
194 return MIstatus::success;
196 CMICMDBASE_GETOPTION(pArgAvailable, OptionLong, m_constStrArgNamedAvailable);
197 CMICMDBASE_GETOPTION(pArgRecurse, OptionLong, m_constStrArgNamedRecurse);
198 CMICMDBASE_GETOPTION(pArgThreadGroup, ThreadGrp,
199 m_constStrArgNamedThreadGroup);
201 // Got some options so "threads"
202 if (pArgAvailable->GetFound()) {
203 if (pArgRecurse->GetFound()) {
204 m_bHaveArgRecurse = true;
205 return MIstatus::success;
208 m_bHaveArgOption = true;
209 return MIstatus::success;
211 // "i1" as first argument (pos 0 of possible arg)
212 if (!pArgThreadGroup->GetFound())
213 return MIstatus::success;
216 CMICmnLLDBDebugSessionInfo &rSessionInfo(
217 CMICmnLLDBDebugSessionInfo::Instance());
218 lldb::SBProcess sbProcess = rSessionInfo.GetProcess();
220 // Note do not check for sbProcess is IsValid(), continue
222 m_vecMIValueTuple.clear();
223 const MIuint nThreads = sbProcess.GetNumThreads();
224 for (MIuint i = 0; i < nThreads; i++) {
225 // GetThreadAtIndex() uses a base 0 index
226 // GetThreadByIndexID() uses a base 1 index
227 lldb::SBThread thread = sbProcess.GetThreadAtIndex(i);
229 if (thread.IsValid()) {
230 CMICmnMIValueTuple miTuple;
231 if (!rSessionInfo.MIResponseFormThreadInfo(
233 CMICmnLLDBDebugSessionInfo::eThreadInfoFormat_NoFrames, miTuple))
234 return MIstatus::failure;
236 m_vecMIValueTuple.push_back(miTuple);
240 return MIstatus::success;
244 // Details: The invoker requires this function. The command prepares a MI Record
246 // for the work carried out in the Execute().
249 // Return: MIstatus::success - Functional succeeded.
250 // MIstatus::failure - Functional failed.
253 bool CMICmdCmdListThreadGroups::Acknowledge() {
254 if (m_bHaveArgOption) {
255 if (m_bHaveArgRecurse) {
256 const CMICmnMIValueConst miValueConst(
257 MIRSRC(IDS_WORD_NOT_IMPLEMENTED_BRKTS));
258 const CMICmnMIValueResult miValueResult("msg", miValueConst);
259 const CMICmnMIResultRecord miRecordResult(
260 m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error,
262 m_miResultRecord = miRecordResult;
264 return MIstatus::success;
267 const CMICmnMIValueConst miValueConst1("i1");
268 const CMICmnMIValueResult miValueResult1("id", miValueConst1);
269 CMICmnMIValueTuple miTuple(miValueResult1);
271 const CMICmnMIValueConst miValueConst2("process");
272 const CMICmnMIValueResult miValueResult2("type", miValueConst2);
273 miTuple.Add(miValueResult2);
275 CMICmnLLDBDebugSessionInfo &rSessionInfo(
276 CMICmnLLDBDebugSessionInfo::Instance());
277 if (rSessionInfo.GetProcess().IsValid()) {
278 const lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID();
279 const CMIUtilString strPid(CMIUtilString::Format("%lld", pid));
280 const CMICmnMIValueConst miValueConst3(strPid);
281 const CMICmnMIValueResult miValueResult3("pid", miValueConst3);
282 miTuple.Add(miValueResult3);
285 const CMICmnMIValueConst miValueConst4(
286 MIRSRC(IDS_WORD_NOT_IMPLEMENTED_BRKTS));
287 const CMICmnMIValueResult miValueResult4("num_children", miValueConst4);
288 miTuple.Add(miValueResult4);
290 const CMICmnMIValueConst miValueConst5(
291 MIRSRC(IDS_WORD_NOT_IMPLEMENTED_BRKTS));
292 const CMICmnMIValueResult miValueResult5("cores", miValueConst5);
293 miTuple.Add(miValueResult5);
295 const CMICmnMIValueList miValueList(miTuple);
296 const CMICmnMIValueResult miValueResult6("groups", miValueList);
297 const CMICmnMIResultRecord miRecordResult(
298 m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done,
300 m_miResultRecord = miRecordResult;
302 return MIstatus::success;
306 const CMICmnMIValueConst miValueConst1("i1");
307 const CMICmnMIValueResult miValueResult1("id", miValueConst1);
308 CMICmnMIValueTuple miTuple(miValueResult1);
310 const CMICmnMIValueConst miValueConst2("process");
311 const CMICmnMIValueResult miValueResult2("type", miValueConst2);
312 miTuple.Add(miValueResult2);
314 CMICmnLLDBDebugSessionInfo &rSessionInfo(
315 CMICmnLLDBDebugSessionInfo::Instance());
316 if (rSessionInfo.GetProcess().IsValid()) {
317 const lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID();
318 const CMIUtilString strPid(CMIUtilString::Format("%lld", pid));
319 const CMICmnMIValueConst miValueConst3(strPid);
320 const CMICmnMIValueResult miValueResult3("pid", miValueConst3);
321 miTuple.Add(miValueResult3);
324 if (rSessionInfo.GetTarget().IsValid()) {
325 lldb::SBTarget sbTrgt = rSessionInfo.GetTarget();
326 const char *pDir = sbTrgt.GetExecutable().GetDirectory();
327 const char *pFileName = sbTrgt.GetExecutable().GetFilename();
328 const CMIUtilString strFile(
329 CMIUtilString::Format("%s/%s",
330 CMIUtilString::WithNullAsEmpty(pDir),
331 CMIUtilString::WithNullAsEmpty(pFileName)));
332 const CMICmnMIValueConst miValueConst4(strFile);
333 const CMICmnMIValueResult miValueResult4("executable", miValueConst4);
334 miTuple.Add(miValueResult4);
337 const CMICmnMIValueList miValueList(miTuple);
338 const CMICmnMIValueResult miValueResult5("groups", miValueList);
339 const CMICmnMIResultRecord miRecordResult(
340 m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done,
342 m_miResultRecord = miRecordResult;
343 return MIstatus::success;
346 // Build up a list of thread information from tuples
347 VecMIValueTuple_t::const_iterator it = m_vecMIValueTuple.begin();
348 if (it == m_vecMIValueTuple.end()) {
349 const CMICmnMIValueConst miValueConst("[]");
350 const CMICmnMIValueResult miValueResult("threads", miValueConst);
351 const CMICmnMIResultRecord miRecordResult(
352 m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done,
354 m_miResultRecord = miRecordResult;
355 return MIstatus::success;
357 CMICmnMIValueList miValueList(*it);
359 while (it != m_vecMIValueTuple.end()) {
360 const CMICmnMIValueTuple &rTuple(*it);
361 miValueList.Add(rTuple);
367 const CMICmnMIValueResult miValueResult("threads", miValueList);
368 const CMICmnMIResultRecord miRecordResult(
369 m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done,
371 m_miResultRecord = miRecordResult;
373 return MIstatus::success;
377 // Details: Required by the CMICmdFactory when registering *this command. The
379 // calls this function to create an instance of *this command.
380 // Type: Static method.
382 // Return: CMICmdBase * - Pointer to a new command.
385 CMICmdBase *CMICmdCmdListThreadGroups::CreateSelf() {
386 return new CMICmdCmdListThreadGroups();
391 // Details: CMICmdCmdInterpreterExec constructor.
397 CMICmdCmdInterpreterExec::CMICmdCmdInterpreterExec()
398 : m_constStrArgNamedInterpreter("interpreter"),
399 m_constStrArgNamedCommand("command") {
400 // Command factory matches this name with that received from the stdin stream
401 m_strMiCmd = "interpreter-exec";
403 // Required by the CMICmdFactory when registering *this command
404 m_pSelfCreatorFn = &CMICmdCmdInterpreterExec::CreateSelf;
408 // Details: CMICmdCmdInterpreterExec destructor.
409 // Type: Overrideable.
414 CMICmdCmdInterpreterExec::~CMICmdCmdInterpreterExec() {}
417 // Details: The invoker requires this function. The parses the command line
419 // arguments to extract values for each of those arguments.
422 // Return: MIstatus::success - Functional succeeded.
423 // MIstatus::failure - Functional failed.
426 bool CMICmdCmdInterpreterExec::ParseArgs() {
428 new CMICmdArgValString(m_constStrArgNamedInterpreter, true, true));
430 new CMICmdArgValString(m_constStrArgNamedCommand, true, true, true));
431 return ParseValidateCmdOptions();
435 // Details: The invoker requires this function. The command does work in this
437 // The command is likely to communicate with the LLDB SBDebugger in
441 // Return: MIstatus::success - Functional succeeded.
442 // MIstatus::failure - Functional failed.
445 bool CMICmdCmdInterpreterExec::Execute() {
446 CMICMDBASE_GETOPTION(pArgInterpreter, String, m_constStrArgNamedInterpreter);
447 CMICMDBASE_GETOPTION(pArgCommand, String, m_constStrArgNamedCommand);
449 // Handle the interpreter parameter by do nothing on purpose (set to 'handled'
450 // in the arg definition above)
451 const CMIUtilString &rStrInterpreter(pArgInterpreter->GetValue());
452 MIunused(rStrInterpreter);
454 const CMIUtilString &rStrCommand(pArgCommand->GetValue());
455 CMICmnLLDBDebugSessionInfo &rSessionInfo(
456 CMICmnLLDBDebugSessionInfo::Instance());
457 const lldb::ReturnStatus rtn =
458 rSessionInfo.GetDebugger().GetCommandInterpreter().HandleCommand(
459 rStrCommand.c_str(), m_lldbResult, true);
462 return MIstatus::success;
466 // Details: The invoker requires this function. The command prepares a MI Record
468 // for the work carried out in the Execute().
471 // Return: MIstatus::success - Functional succeeded.
472 // MIstatus::failure - Functional failed.
475 bool CMICmdCmdInterpreterExec::Acknowledge() {
476 if (m_lldbResult.GetOutputSize() > 0) {
477 const CMIUtilString line(m_lldbResult.GetOutput());
478 const bool bEscapeQuotes(true);
479 CMICmnMIValueConst miValueConst(line.Escape(bEscapeQuotes));
480 CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_ConsoleStreamOutput, miValueConst);
481 const bool bOk = CMICmnStreamStdout::TextToStdout(miOutOfBandRecord.GetString());
483 return MIstatus::failure;
485 if (m_lldbResult.GetErrorSize() > 0) {
486 const CMIUtilString line(m_lldbResult.GetError());
487 const bool bEscapeQuotes(true);
488 CMICmnMIValueConst miValueConst(line.Escape(bEscapeQuotes));
489 CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_LogStreamOutput, miValueConst);
490 const bool bOk = CMICmnStreamStdout::TextToStdout(miOutOfBandRecord.GetString());
492 return MIstatus::failure;
495 const CMICmnMIResultRecord miRecordResult(
496 m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done);
497 m_miResultRecord = miRecordResult;
499 return MIstatus::success;
503 // Details: Required by the CMICmdFactory when registering *this command. The
505 // calls this function to create an instance of *this command.
506 // Type: Static method.
508 // Return: CMICmdBase * - Pointer to a new command.
511 CMICmdBase *CMICmdCmdInterpreterExec::CreateSelf() {
512 return new CMICmdCmdInterpreterExec();
517 // Details: CMICmdCmdInferiorTtySet constructor.
523 CMICmdCmdInferiorTtySet::CMICmdCmdInferiorTtySet() {
524 // Command factory matches this name with that received from the stdin stream
525 m_strMiCmd = "inferior-tty-set";
527 // Required by the CMICmdFactory when registering *this command
528 m_pSelfCreatorFn = &CMICmdCmdInferiorTtySet::CreateSelf;
532 // Details: CMICmdCmdInferiorTtySet destructor.
533 // Type: Overrideable.
538 CMICmdCmdInferiorTtySet::~CMICmdCmdInferiorTtySet() {}
541 // Details: The invoker requires this function. The command does work in this
543 // The command is likely to communicate with the LLDB SBDebugger in
547 // Return: MIstatus::success - Functional succeeded.
548 // MIstatus::failure - Functional failed.
551 bool CMICmdCmdInferiorTtySet::Execute() {
554 return MIstatus::success;
558 // Details: The invoker requires this function. The command prepares a MI Record
560 // for the work carried out in the Execute().
563 // Return: MIstatus::success - Functional succeeded.
564 // MIstatus::failure - Functional failed.
567 bool CMICmdCmdInferiorTtySet::Acknowledge() {
568 const CMICmnMIResultRecord miRecordResult(
569 m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error);
570 m_miResultRecord = miRecordResult;
572 return MIstatus::success;
576 // Details: Required by the CMICmdFactory when registering *this command. The
578 // calls this function to create an instance of *this command.
579 // Type: Static method.
581 // Return: CMICmdBase * - Pointer to a new command.
584 CMICmdBase *CMICmdCmdInferiorTtySet::CreateSelf() {
585 return new CMICmdCmdInferiorTtySet();