1 //===-- MICmdCmdThread.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: CMICmdCmdThreadInfo implementation.
11 // Third Party Headers:
12 #include "lldb/API/SBBreakpointLocation.h"
13 #include "lldb/API/SBThread.h"
16 #include "MICmdArgValNumber.h"
17 #include "MICmdCmdThread.h"
18 #include "MICmnLLDBDebugSessionInfo.h"
19 #include "MICmnLLDBDebugger.h"
20 #include "MICmnMIResultRecord.h"
21 #include "MICmnMIValueConst.h"
24 // Details: CMICmdCmdThreadInfo constructor.
30 CMICmdCmdThreadInfo::CMICmdCmdThreadInfo()
31 : m_bSingleThread(false), m_bThreadInvalid(true),
32 m_constStrArgNamedThreadId("thread-id"), m_bHasCurrentThread(false) {
33 // Command factory matches this name with that received from the stdin stream
34 m_strMiCmd = "thread-info";
36 // Required by the CMICmdFactory when registering *this command
37 m_pSelfCreatorFn = &CMICmdCmdThreadInfo::CreateSelf;
41 // Details: CMICmdCmdThreadInfo destructor.
42 // Type: Overrideable.
47 CMICmdCmdThreadInfo::~CMICmdCmdThreadInfo() { m_vecMIValueTuple.clear(); }
50 // Details: The invoker requires this function. The parses the command line
52 // arguments to extract values for each of those arguments.
55 // Return: MIstatus::success - Functional succeeded.
56 // MIstatus::failure - Functional failed.
59 bool CMICmdCmdThreadInfo::ParseArgs() {
61 new CMICmdArgValNumber(m_constStrArgNamedThreadId, false, true));
62 return ParseValidateCmdOptions();
66 // Details: The invoker requires this function. The command does work in this
68 // The command is likely to communicate with the LLDB SBDebugger in
72 // Return: MIstatus::success - Functional succeeded.
73 // MIstatus::failure - Functional failed.
76 bool CMICmdCmdThreadInfo::Execute() {
77 CMICMDBASE_GETOPTION(pArgThreadId, Number, m_constStrArgNamedThreadId);
79 if (pArgThreadId->GetFound() && pArgThreadId->GetValid()) {
80 m_bSingleThread = true;
81 nThreadId = static_cast<MIuint>(pArgThreadId->GetValue());
84 CMICmnLLDBDebugSessionInfo &rSessionInfo(
85 CMICmnLLDBDebugSessionInfo::Instance());
86 lldb::SBProcess sbProcess = rSessionInfo.GetProcess();
87 lldb::SBThread thread = sbProcess.GetSelectedThread();
89 if (m_bSingleThread) {
90 thread = sbProcess.GetThreadByIndexID(nThreadId);
91 m_bThreadInvalid = !thread.IsValid();
93 return MIstatus::success;
95 CMICmnMIValueTuple miTuple;
96 if (!rSessionInfo.MIResponseFormThreadInfo(
98 CMICmnLLDBDebugSessionInfo::eThreadInfoFormat_AllFrames, miTuple))
99 return MIstatus::failure;
101 m_miValueTupleThread = miTuple;
103 return MIstatus::success;
107 m_vecMIValueTuple.clear();
108 const MIuint nThreads = sbProcess.GetNumThreads();
109 for (MIuint i = 0; i < nThreads; i++) {
110 lldb::SBThread thread = sbProcess.GetThreadAtIndex(i);
111 if (thread.IsValid()) {
112 CMICmnMIValueTuple miTuple;
113 if (!rSessionInfo.MIResponseFormThreadInfo(
115 CMICmnLLDBDebugSessionInfo::eThreadInfoFormat_AllFrames, miTuple))
116 return MIstatus::failure;
118 m_vecMIValueTuple.push_back(miTuple);
122 // -thread-info with multiple threads ends with the current thread id if any
123 if (thread.IsValid()) {
124 const CMIUtilString strId(CMIUtilString::Format("%d", thread.GetIndexID()));
125 CMICmnMIValueConst miValueCurrThreadId(strId);
126 m_miValueCurrThreadId = miValueCurrThreadId;
127 m_bHasCurrentThread = true;
130 return MIstatus::success;
134 // Details: The invoker requires this function. The command prepares a MI Record
136 // for the work carried out in the Execute().
139 // Return: MIstatus::success - Functional succeeded.
140 // MIstatus::failure - Functional failed.
143 bool CMICmdCmdThreadInfo::Acknowledge() {
144 if (m_bSingleThread) {
145 if (m_bThreadInvalid) {
146 const CMICmnMIValueConst miValueConst("invalid thread id");
147 const CMICmnMIValueResult miValueResult("msg", miValueConst);
148 const CMICmnMIResultRecord miRecordResult(
149 m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error,
151 m_miResultRecord = miRecordResult;
152 return MIstatus::success;
156 // "%s^done,threads=[{id=\"%d\",target-id=\"%s\",frame={},state=\"%s\"}]
157 const CMICmnMIValueList miValueList(m_miValueTupleThread);
158 const CMICmnMIValueResult miValueResult("threads", miValueList);
159 const CMICmnMIResultRecord miRecordResult(
160 m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done,
162 m_miResultRecord = miRecordResult;
163 return MIstatus::success;
166 // Build up a list of thread information from tuples
167 VecMIValueTuple_t::const_iterator it = m_vecMIValueTuple.begin();
168 if (it == m_vecMIValueTuple.end()) {
169 const CMICmnMIValueConst miValueConst("[]");
170 const CMICmnMIValueResult miValueResult("threads", miValueConst);
171 const CMICmnMIResultRecord miRecordResult(
172 m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done,
174 m_miResultRecord = miRecordResult;
175 return MIstatus::success;
177 CMICmnMIValueList miValueList(*it);
179 while (it != m_vecMIValueTuple.end()) {
180 const CMICmnMIValueTuple &rTuple(*it);
181 miValueList.Add(rTuple);
187 CMICmnMIValueResult miValueResult("threads", miValueList);
188 if (m_bHasCurrentThread) {
189 CMIUtilString strCurrThreadId = "current-thread-id";
190 miValueResult.Add(strCurrThreadId, m_miValueCurrThreadId);
192 const CMICmnMIResultRecord miRecordResult(
193 m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done,
195 m_miResultRecord = miRecordResult;
197 return MIstatus::success;
201 // Details: Required by the CMICmdFactory when registering *this command. The
203 // calls this function to create an instance of *this command.
204 // Type: Static method.
206 // Return: CMICmdBase * - Pointer to a new command.
209 CMICmdBase *CMICmdCmdThreadInfo::CreateSelf() {
210 return new CMICmdCmdThreadInfo();