]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/tools/lldb-mi/MICmdInvoker.cpp
Merge OpenSSL 1.0.2e.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / tools / lldb-mi / MICmdInvoker.cpp
1 //===-- MICmdInvoker.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 // In-house headers:
11 #include "MICmdInvoker.h"
12 #include "MICmdBase.h"
13 #include "MICmdMgr.h"
14 #include "MICmnLog.h"
15 #include "MICmnStreamStdout.h"
16 #include "MIDriver.h"
17
18 //++ ------------------------------------------------------------------------------------
19 // Details: CMICmdInvoker constructor.
20 // Type:    Method.
21 // Args:    None.
22 // Return:  None.
23 // Throws:  None.
24 //--
25 CMICmdInvoker::CMICmdInvoker(void)
26     : m_rStreamOut(CMICmnStreamStdout::Instance())
27 {
28 }
29
30 //++ ------------------------------------------------------------------------------------
31 // Details: CMICmdInvoker destructor.
32 // Type:    Overridable.
33 // Args:    None.
34 // Return:  None.
35 // Throws:  None.
36 //--
37 CMICmdInvoker::~CMICmdInvoker(void)
38 {
39     Shutdown();
40 }
41
42 //++ ------------------------------------------------------------------------------------
43 // Details: Initialize resources for *this Command Invoker.
44 // Type:    Method.
45 // Args:    None.
46 // Return:  MIstatus::success - Functional succeeded.
47 //          MIstatus::failure - Functional failed.
48 // Throws:  None.
49 //--
50 bool
51 CMICmdInvoker::Initialize(void)
52 {
53     m_clientUsageRefCnt++;
54
55     if (m_bInitialized)
56         return MIstatus::success;
57
58     m_bInitialized = true;
59
60     return MIstatus::success;
61 }
62
63 //++ ------------------------------------------------------------------------------------
64 // Details: Release resources for *this Stdin stream.
65 // Type:    Method.
66 // Args:    None.
67 // Return:  MIstatus::success - Functional succeeded.
68 //          MIstatus::failure - Functional failed.
69 // Throws:  None.
70 //--
71 bool
72 CMICmdInvoker::Shutdown(void)
73 {
74     if (--m_clientUsageRefCnt > 0)
75         return MIstatus::success;
76
77     if (!m_bInitialized)
78         return MIstatus::success;
79
80     CmdDeleteAll();
81
82     m_bInitialized = false;
83
84     return MIstatus::success;
85 }
86
87 //++ ------------------------------------------------------------------------------------
88 // Details: Empty the map of invoked commands doing work. Command objects are deleted too.
89 // Type:    Method.
90 // Args:    None.
91 // Return:  None.
92 // Throws:  None.
93 //--
94 void
95 CMICmdInvoker::CmdDeleteAll(void)
96 {
97     CMICmdMgr &rMgr = CMICmdMgr::Instance();
98     MapCmdIdToCmd_t::const_iterator it = m_mapCmdIdToCmd.begin();
99     while (it != m_mapCmdIdToCmd.end())
100     {
101         const MIuint cmdId((*it).first);
102         MIunused(cmdId);
103         CMICmdBase *pCmd = (*it).second;
104         const CMIUtilString &rCmdName(pCmd->GetCmdData().strMiCmd);
105         MIunused(rCmdName);
106         rMgr.CmdDelete(pCmd->GetCmdData());
107
108         // Next
109         ++it;
110     }
111     m_mapCmdIdToCmd.clear();
112 }
113
114 //++ ------------------------------------------------------------------------------------
115 // Details: Remove from the map of invoked commands doing work a command that has finished
116 //          its work. The command object is deleted too.
117 // Type:    Method.
118 // Args:    vId             - (R) Command object's unique ID.
119 //          vbYesDeleteCmd  - (R) True = Delete command object, false = delete via the Command Manager.
120 // Return:  None.
121 // Throws:  None.
122 //--
123 bool
124 CMICmdInvoker::CmdDelete(const MIuint vId, const bool vbYesDeleteCmd /*= false*/)
125 {
126     CMICmdMgr &rMgr = CMICmdMgr::Instance();
127     MapCmdIdToCmd_t::const_iterator it = m_mapCmdIdToCmd.find(vId);
128     if (it != m_mapCmdIdToCmd.end())
129     {
130         CMICmdBase *pCmd = (*it).second;
131         if (vbYesDeleteCmd)
132         {
133             // Via registered interest command manager callback *this object to delete the command
134             m_mapCmdIdToCmd.erase(it);
135             delete pCmd;
136         }
137         else
138             // Notify other interested object of this command's pending deletion
139             rMgr.CmdDelete(pCmd->GetCmdData());
140     }
141
142     if (m_mapCmdIdToCmd.empty())
143         rMgr.CmdUnregisterForDeleteNotification(*this);
144
145     return MIstatus::success;
146 }
147
148 //++ ------------------------------------------------------------------------------------
149 // Details: Add to the map of invoked commands doing work a command that is about to
150 //          start to do work.
151 // Type:    Method.
152 // Args:    vCmd    - (R) Command object.
153 // Return:  None.
154 // Throws:  None.
155 //--
156 bool
157 CMICmdInvoker::CmdAdd(const CMICmdBase &vCmd)
158 {
159     if (m_mapCmdIdToCmd.empty())
160     {
161         CMICmdMgr &rMgr = CMICmdMgr::Instance();
162         rMgr.CmdRegisterForDeleteNotification(*this);
163     }
164
165     const MIuint &cmdId(vCmd.GetCmdData().id);
166     MapCmdIdToCmd_t::const_iterator it = m_mapCmdIdToCmd.find(cmdId);
167     if (it != m_mapCmdIdToCmd.end())
168         return MIstatus::success;
169
170     MapPairCmdIdToCmd_t pr(cmdId, const_cast<CMICmdBase *>(&vCmd));
171     m_mapCmdIdToCmd.insert(pr);
172
173     return MIstatus::success;
174 }
175
176 //++ ------------------------------------------------------------------------------------
177 // Details: Having previously had the potential command validated and found valid now
178 //          get the command executed.
179 //          If the Functionality returns MIstatus::failure call GetErrorDescription().
180 //          This function is used by the application's main thread.
181 // Type:    Method.
182 // Args:    vCmd    - (RW) Command object.
183 // Return:  MIstatus::success - Functionality succeeded.
184 //          MIstatus::failure - Functionality failed.
185 // Throws:  None.
186 //--
187 bool
188 CMICmdInvoker::CmdExecute(CMICmdBase &vCmd)
189 {
190     bool bOk = CmdAdd(vCmd);
191
192     if (bOk && !vCmd.ParseArgs())
193     {
194         // Report command execution failed
195         const SMICmdData cmdData(vCmd.GetCmdData());
196         CmdStdout(cmdData);
197         CmdCauseAppExit(vCmd);
198         CmdDelete(cmdData.id);
199
200         // Proceed to wait or execute next command
201         return MIstatus::success;
202     }
203
204     if (bOk && !vCmd.Execute())
205     {
206         // Report command execution failed
207         const SMICmdData cmdData(vCmd.GetCmdData());
208         CmdStdout(cmdData);
209         CmdCauseAppExit(vCmd);
210         CmdDelete(cmdData.id);
211
212         // Proceed to wait or execute next command
213         return MIstatus::success;
214     }
215
216     bOk = CmdExecuteFinished(vCmd);
217
218     return bOk;
219 }
220
221 //++ ------------------------------------------------------------------------------------
222 // Details: Called when a command has finished its Execution() work either synchronously
223 //          because the command executed was the type a non event type or asynchronously
224 //          via the command's callback (because of an SB Listener event). Needs to be called
225 //          so that *this invoker call do some house keeping and then proceed to call
226 //          the command's Acknowledge() function.
227 // Type:    Method.
228 // Args:    vCmd    - (R) Command object.
229 // Return:  MIstatus::success - Functionality succeeded.
230 //          MIstatus::failure - Functionality failed.
231 // Throws:  None.
232 //--
233 bool
234 CMICmdInvoker::CmdExecuteFinished(CMICmdBase &vCmd)
235 {
236     // Command finished now get the command to gather it's information and form the MI
237     // Result record
238     if (!vCmd.Acknowledge())
239     {
240         // Report command acknowledge functionality failed
241         const SMICmdData cmdData(vCmd.GetCmdData());
242         CmdStdout(cmdData);
243         CmdCauseAppExit(vCmd);
244         CmdDelete(cmdData.id);
245
246         // Proceed to wait or execute next command
247         return MIstatus::success;
248     }
249
250     // Retrieve the command's latest data/information. Needed for commands of the event type so have
251     // a record of commands pending finishing execution.
252     const CMIUtilString &rMIResultRecord(vCmd.GetMIResultRecord());
253     SMICmdData cmdData(vCmd.GetCmdData());          // Make a copy as the command will be deleted soon
254     cmdData.strMiCmdResultRecord = rMIResultRecord; // Precautionary copy as the command might forget to do this
255     if (vCmd.HasMIResultRecordExtra())
256     {
257         cmdData.bHasResultRecordExtra = true;
258         const CMIUtilString &rMIExtra(vCmd.GetMIResultRecordExtra());
259         cmdData.strMiCmdResultRecordExtra = rMIExtra; // Precautionary copy as the command might forget to do this
260     }
261
262     // Send command's MI response to the client
263     bool bOk = CmdStdout(cmdData);
264
265     // Delete the command object as do not require anymore
266     bOk = bOk && CmdDelete(vCmd.GetCmdData().id);
267
268     return bOk;
269 }
270
271 //++ ------------------------------------------------------------------------------------
272 // Details: If the MI Driver is not operating via a client i.e. Eclipse check the command
273 //          on failure suggests the application exits. A command can be such that a
274 //          failure cannot the allow the application to continue operating.
275 // Args:    vCmd    - (R) Command object.
276 // Return:  None.
277 // Return:  None.
278 // Throws:  None.
279 //--
280 void
281 CMICmdInvoker::CmdCauseAppExit(const CMICmdBase &vCmd) const
282 {
283     if (vCmd.GetExitAppOnCommandFailure())
284     {
285         CMIDriver &rDriver(CMIDriver::Instance());
286         if (rDriver.IsDriverDebuggingArgExecutable())
287         {
288             rDriver.SetExitApplicationFlag(true);
289         }
290     }
291 }
292
293 //++ ------------------------------------------------------------------------------------
294 // Details: Write to stdout and the Log file the command's MI formatted result.
295 // Type:    vCmdData    - (R) A command's information.
296 // Return:  MIstatus::success - Functionality succeeded.
297 //          MIstatus::failure - Functionality failed.
298 // Return:  None.
299 // Throws:  None.
300 //--
301 bool
302 CMICmdInvoker::CmdStdout(const SMICmdData &vCmdData) const
303 {
304     bool bOk = m_pLog->WriteLog(vCmdData.strMiCmdAll);
305     const bool bLock = bOk && m_rStreamOut.Lock();
306     bOk = bOk && bLock && m_rStreamOut.WriteMIResponse(vCmdData.strMiCmdResultRecord);
307     if (bOk && vCmdData.bHasResultRecordExtra)
308     {
309         bOk = m_rStreamOut.WriteMIResponse(vCmdData.strMiCmdResultRecordExtra);
310     }
311     bOk = bLock && m_rStreamOut.Unlock();
312
313     return bOk;
314 }
315
316 //++ ------------------------------------------------------------------------------------
317 // Details: Required by the CMICmdMgr::ICmdDeleteCallback. *this object is registered
318 //          with the Command Manager to receive callbacks when a command is being deleted.
319 //          An object, *this invoker, does not delete a command object itself but calls
320 //          the Command Manager to delete a command object. This function is the Invoker's
321 //          called.
322 //          The Invoker owns the command objects and so can delete them but must do it
323 //          via the manager so other objects can be notified of the deletion.
324 // Type:    Method.
325 // Args:    vCmd    - (RW) Command.
326 // Return:  None.
327 // Throws:  None.
328 //--
329 void
330 CMICmdInvoker::Delete(SMICmdData &vCmd)
331 {
332     CmdDelete(vCmd.id, true);
333 }