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