1 //===-- MICmdCmdThread.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: CMICmdCmdThreadInfo implementation.
11
12 // Third Party Headers:
13 #include "lldb/API/SBBreakpointLocation.h"
14 #include "lldb/API/SBThread.h"
15
16 // In-house headers:
17 #include "MICmdArgValNumber.h"
18 #include "MICmdCmdThread.h"
19 #include "MICmnLLDBDebugSessionInfo.h"
20 #include "MICmnLLDBDebugger.h"
21 #include "MICmnMIResultRecord.h"
22 #include "MICmnMIValueConst.h"
23
24 //++
25 //------------------------------------------------------------------------------------
26 // Details: CMICmdCmdThreadInfo constructor.
27 // Type: Method.
28 // Args: None.
29 // Return: None.
30 // Throws: None.
31 //--
CMICmdCmdThreadInfo()32 CMICmdCmdThreadInfo::CMICmdCmdThreadInfo()
33 : m_bSingleThread(false), m_bThreadInvalid(true),
34 m_constStrArgNamedThreadId("thread-id"), m_bHasCurrentThread(false) {
35 // Command factory matches this name with that received from the stdin stream
36 m_strMiCmd = "thread-info";
37
38 // Required by the CMICmdFactory when registering *this command
39 m_pSelfCreatorFn = &CMICmdCmdThreadInfo::CreateSelf;
40 }
41
42 //++
43 //------------------------------------------------------------------------------------
44 // Details: CMICmdCmdThreadInfo destructor.
45 // Type: Overrideable.
46 // Args: None.
47 // Return: None.
48 // Throws: None.
49 //--
~CMICmdCmdThreadInfo()50 CMICmdCmdThreadInfo::~CMICmdCmdThreadInfo() { m_vecMIValueTuple.clear(); }
51
52 //++
53 //------------------------------------------------------------------------------------
54 // Details: The invoker requires this function. The parses the command line
55 // options
56 // arguments to extract values for each of those arguments.
57 // Type: Overridden.
58 // Args: None.
59 // Return: MIstatus::success - Functional succeeded.
60 // MIstatus::failure - Functional failed.
61 // Throws: None.
62 //--
ParseArgs()63 bool CMICmdCmdThreadInfo::ParseArgs() {
64 m_setCmdArgs.Add(
65 new CMICmdArgValNumber(m_constStrArgNamedThreadId, false, true));
66 return ParseValidateCmdOptions();
67 }
68
69 //++
70 //------------------------------------------------------------------------------------
71 // Details: The invoker requires this function. The command does work in this
72 // function.
73 // The command is likely to communicate with the LLDB SBDebugger in
74 // here.
75 // Type: Overridden.
76 // Args: None.
77 // Return: MIstatus::success - Functional succeeded.
78 // MIstatus::failure - Functional failed.
79 // Throws: None.
80 //--
Execute()81 bool CMICmdCmdThreadInfo::Execute() {
82 CMICMDBASE_GETOPTION(pArgThreadId, Number, m_constStrArgNamedThreadId);
83 MIuint nThreadId = 0;
84 if (pArgThreadId->GetFound() && pArgThreadId->GetValid()) {
85 m_bSingleThread = true;
86 nThreadId = static_cast<MIuint>(pArgThreadId->GetValue());
87 }
88
89 CMICmnLLDBDebugSessionInfo &rSessionInfo(
90 CMICmnLLDBDebugSessionInfo::Instance());
91 lldb::SBProcess sbProcess = rSessionInfo.GetProcess();
92 lldb::SBThread thread = sbProcess.GetSelectedThread();
93
94 if (m_bSingleThread) {
95 thread = sbProcess.GetThreadByIndexID(nThreadId);
96 m_bThreadInvalid = !thread.IsValid();
97 if (m_bThreadInvalid)
98 return MIstatus::success;
99
100 CMICmnMIValueTuple miTuple;
101 if (!rSessionInfo.MIResponseFormThreadInfo(
102 m_cmdData, thread,
103 CMICmnLLDBDebugSessionInfo::eThreadInfoFormat_AllFrames, miTuple))
104 return MIstatus::failure;
105
106 m_miValueTupleThread = miTuple;
107
108 return MIstatus::success;
109 }
110
111 // Multiple threads
112 m_vecMIValueTuple.clear();
113 const MIuint nThreads = sbProcess.GetNumThreads();
114 for (MIuint i = 0; i < nThreads; i++) {
115 lldb::SBThread thread = sbProcess.GetThreadAtIndex(i);
116 if (thread.IsValid()) {
117 CMICmnMIValueTuple miTuple;
118 if (!rSessionInfo.MIResponseFormThreadInfo(
119 m_cmdData, thread,
120 CMICmnLLDBDebugSessionInfo::eThreadInfoFormat_AllFrames, miTuple))
121 return MIstatus::failure;
122
123 m_vecMIValueTuple.push_back(miTuple);
124 }
125 }
126
127 // -thread-info with multiple threads ends with the current thread id if any
128 if (thread.IsValid()) {
129 const CMIUtilString strId(CMIUtilString::Format("%d", thread.GetIndexID()));
130 CMICmnMIValueConst miValueCurrThreadId(strId);
131 m_miValueCurrThreadId = miValueCurrThreadId;
132 m_bHasCurrentThread = true;
133 }
134
135 return MIstatus::success;
136 }
137
138 //++
139 //------------------------------------------------------------------------------------
140 // Details: The invoker requires this function. The command prepares a MI Record
141 // Result
142 // for the work carried out in the Execute().
143 // Type: Overridden.
144 // Args: None.
145 // Return: MIstatus::success - Functional succeeded.
146 // MIstatus::failure - Functional failed.
147 // Throws: None.
148 //--
Acknowledge()149 bool CMICmdCmdThreadInfo::Acknowledge() {
150 if (m_bSingleThread) {
151 if (m_bThreadInvalid) {
152 const CMICmnMIValueConst miValueConst("invalid thread id");
153 const CMICmnMIValueResult miValueResult("msg", miValueConst);
154 const CMICmnMIResultRecord miRecordResult(
155 m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error,
156 miValueResult);
157 m_miResultRecord = miRecordResult;
158 return MIstatus::success;
159 }
160
161 // MI print
162 // "%s^done,threads=[{id=\"%d\",target-id=\"%s\",frame={},state=\"%s\"}]
163 const CMICmnMIValueList miValueList(m_miValueTupleThread);
164 const CMICmnMIValueResult miValueResult("threads", miValueList);
165 const CMICmnMIResultRecord miRecordResult(
166 m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done,
167 miValueResult);
168 m_miResultRecord = miRecordResult;
169 return MIstatus::success;
170 }
171
172 // Build up a list of thread information from tuples
173 VecMIValueTuple_t::const_iterator it = m_vecMIValueTuple.begin();
174 if (it == m_vecMIValueTuple.end()) {
175 const CMICmnMIValueConst miValueConst("[]");
176 const CMICmnMIValueResult miValueResult("threads", miValueConst);
177 const CMICmnMIResultRecord miRecordResult(
178 m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done,
179 miValueResult);
180 m_miResultRecord = miRecordResult;
181 return MIstatus::success;
182 }
183 CMICmnMIValueList miValueList(*it);
184 ++it;
185 while (it != m_vecMIValueTuple.end()) {
186 const CMICmnMIValueTuple &rTuple(*it);
187 miValueList.Add(rTuple);
188
189 // Next
190 ++it;
191 }
192
193 CMICmnMIValueResult miValueResult("threads", miValueList);
194 if (m_bHasCurrentThread) {
195 CMIUtilString strCurrThreadId = "current-thread-id";
196 miValueResult.Add(strCurrThreadId, m_miValueCurrThreadId);
197 }
198 const CMICmnMIResultRecord miRecordResult(
199 m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done,
200 miValueResult);
201 m_miResultRecord = miRecordResult;
202
203 return MIstatus::success;
204 }
205
206 //++
207 //------------------------------------------------------------------------------------
208 // Details: Required by the CMICmdFactory when registering *this command. The
209 // factory
210 // calls this function to create an instance of *this command.
211 // Type: Static method.
212 // Args: None.
213 // Return: CMICmdBase * - Pointer to a new command.
214 // Throws: None.
215 //--
CreateSelf()216 CMICmdBase *CMICmdCmdThreadInfo::CreateSelf() {
217 return new CMICmdCmdThreadInfo();
218 }
219