]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/lldb-mi/MICmnLLDBDebugger.cpp
Import LLDB as of upstream SVN r216948 (git 50f7fe44)
[FreeBSD/FreeBSD.git] / tools / lldb-mi / MICmnLLDBDebugger.cpp
1 //===-- MICmnLLDBDebugger.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:                MICmnLLDBDebugger.cpp
12 //
13 // Overview:    CMICmnLLDBDebugger 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 // Third party headers:
23 #include <lldb/API/SBTarget.h>
24 #include <lldb/API/SBThread.h> 
25 #include <lldb/API/SBProcess.h>
26 #include <lldb/API/SBCommandInterpreter.h>
27
28 // In-house headers:
29 #include "MICmnLLDBDebugger.h"
30 #include "MICmnResources.h"
31 #include "MICmnLog.h"
32 #include "MIDriverBase.h"
33 #include "MICmnThreadMgrStd.h"
34 #include "MICmnLLDBDebuggerHandleEvents.h"
35 #include "MICmnLLDBDebugSessionInfo.h"
36 #include "MIUtilSingletonHelper.h"
37
38 //++ ------------------------------------------------------------------------------------
39 // Details:     CMICmnLLDBDebugger constructor.
40 // Type:        Method.
41 // Args:        None.
42 // Return:      None.
43 // Throws:      None.
44 //--
45 CMICmnLLDBDebugger::CMICmnLLDBDebugger( void )
46 :       m_constStrThisThreadId( "MI debugger event" )
47 {
48 }
49
50 //++ ------------------------------------------------------------------------------------
51 // Details:     CMICmnLLDBDebugger destructor.
52 // Type:        Overridable.
53 // Args:        None.
54 // Return:      None.
55 // Throws:      None.
56 //--
57 CMICmnLLDBDebugger::~CMICmnLLDBDebugger( void )
58 {
59         Shutdown();
60 }
61
62 //++ ------------------------------------------------------------------------------------
63 // Details:     Initialize resources for *this debugger object.
64 // Type:        Method.
65 // Args:        None.
66 // Return:      MIstatus::success - Functionality succeeded.
67 //                      MIstatus::failure - Functionality failed.
68 // Throws:      None.
69 //--
70 bool CMICmnLLDBDebugger::Initialize( void )
71 {
72         m_clientUsageRefCnt++;
73
74         if( m_bInitialized )
75                 return MIstatus::success;
76
77         bool bOk = MIstatus::success;
78         CMIUtilString errMsg;
79         ClrErrorDescription();
80
81         if( m_pClientDriver == nullptr )
82         {
83                 bOk = false;
84                 errMsg = MIRSRC( IDS_LLDBDEBUGGER_ERR_CLIENTDRIVER );
85         }
86         
87         // Note initialization order is important here as some resources depend on previous
88         MI::ModuleInit< CMICmnLog >                     ( IDS_MI_INIT_ERR_LOG             , bOk, errMsg );
89         MI::ModuleInit< CMICmnResources >               ( IDS_MI_INIT_ERR_RESOURCES       , bOk, errMsg );
90         MI::ModuleInit< CMICmnThreadMgrStd >            ( IDS_MI_INIT_ERR_THREADMGR       , bOk, errMsg );
91         MI::ModuleInit< CMICmnLLDBDebuggerHandleEvents >( IDS_MI_INIT_ERR_OUTOFBANDHANDLER, bOk, errMsg );
92         MI::ModuleInit< CMICmnLLDBDebugSessionInfo >    ( IDS_MI_INIT_ERR_DEBUGSESSIONINFO, bOk, errMsg );
93
94         // Note order is important here!
95         if( bOk )
96                 lldb::SBDebugger::Initialize();
97         if( bOk && !InitSBDebugger() )
98         {
99                 bOk = false;
100                 if( !errMsg.empty() ) errMsg += ", ";
101                 errMsg += GetErrorDescription().c_str();
102         }
103         if( bOk && !InitSBListener() )
104         {
105                 bOk = false;
106                 if( !errMsg.empty() ) errMsg += ", ";
107                 errMsg += GetErrorDescription().c_str();
108         }
109         bOk = bOk && InitStdStreams();
110
111         m_bInitialized = bOk;
112
113         if( !bOk && !HaveErrorDescription() )
114         {
115                 CMIUtilString strInitError( CMIUtilString::Format( MIRSRC( IDS_MI_INIT_ERR_LLDBDEBUGGER ), errMsg.c_str() ) );
116                 SetErrorDescription( strInitError );
117         }
118
119         return bOk;
120 }
121
122 //++ ------------------------------------------------------------------------------------
123 // Details:     Release resources for *this debugger object.
124 // Type:        Method.
125 // Args:        None.
126 // Return:      MIstatus::success - Functionality succeeded.
127 //                      MIstatus::failure - Functionality failed.
128 // Throws:      None.
129 //--
130 bool CMICmnLLDBDebugger::Shutdown( void )
131 {
132         if( --m_clientUsageRefCnt > 0 )
133                 return MIstatus::success;
134         
135         if( !m_bInitialized )
136                 return MIstatus::success;
137
138         m_bInitialized = false;
139
140         ClrErrorDescription();
141
142         bool bOk = MIstatus::success;
143         CMIUtilString errMsg;
144                                         
145         // Explicitly delete the remote target in case MI needs to exit prematurely otherwise 
146         // LLDB debugger may hang in its Destroy() fn waiting on events
147         m_lldbDebugger.DeleteTarget( CMICmnLLDBDebugSessionInfo::Instance().m_lldbTarget );
148
149         // Debug: May need this but does seem to work without it so commented out the fudge 19/06/2014
150         // It appears we need to wait as hang does not occur when hitting a debug breakpoint here
151         //const std::chrono::milliseconds time( 1000 );
152         //std::this_thread::sleep_for( time );
153                 
154         lldb::SBDebugger::Destroy( m_lldbDebugger );
155         lldb::SBDebugger::Terminate();
156         m_pClientDriver = nullptr;
157         m_mapBroadcastClassNameToEventMask.clear();
158         m_mapIdToEventMask.clear();
159
160         // Note shutdown order is important here
161         MI::ModuleShutdown< CMICmnLLDBDebugSessionInfo >    ( IDS_MI_INIT_ERR_DEBUGSESSIONINFO, bOk, errMsg );
162         MI::ModuleShutdown< CMICmnLLDBDebuggerHandleEvents >( IDS_MI_INIT_ERR_OUTOFBANDHANDLER, bOk, errMsg );
163         MI::ModuleShutdown< CMICmnThreadMgrStd >            ( IDS_MI_INIT_ERR_THREADMGR       , bOk, errMsg );
164         MI::ModuleShutdown< CMICmnResources >               ( IDS_MI_INIT_ERR_RESOURCES       , bOk, errMsg );
165         MI::ModuleShutdown< CMICmnLog >                     ( IDS_MI_INIT_ERR_LOG             , bOk, errMsg );
166
167         if( !bOk )
168         {
169                 SetErrorDescriptionn( MIRSRC( IDS_MI_SHTDWN_ERR_LLDBDEBUGGER ), errMsg.c_str() );
170         }
171
172         return MIstatus::success;
173 }       
174
175 //++ ------------------------------------------------------------------------------------
176 // Details:     Return the LLDB debugger instance created for this debug session.
177 // Type:        Method.
178 // Args:        None.
179 // Return:      lldb::SBDebugger & - LLDB debugger object reference.
180 // Throws:      None.
181 //--
182 lldb::SBDebugger & CMICmnLLDBDebugger::GetTheDebugger( void )
183 {
184         return m_lldbDebugger;
185 }
186
187 //++ ------------------------------------------------------------------------------------
188 // Details:     Return the LLDB listener instance created for this debug session.
189 // Type:        Method.
190 // Args:        None.
191 // Return:      lldb::SBListener & - LLDB listener object reference.
192 // Throws:      None.
193 //--
194 lldb::SBListener & CMICmnLLDBDebugger::GetTheListener( void )
195 {
196         return m_lldbListener;
197 }
198
199 //++ ------------------------------------------------------------------------------------
200 // Details:     Set the client driver that wants to use *this LLDB debugger. Call this function
201 //                      prior to Initialize().
202 // Type:        Method.
203 // Args:        vClientDriver   - (R) A driver.
204 // Return:      MIstatus::success - Functionality succeeded.
205 //                      MIstatus::failure - Functionality failed.
206 // Throws:      None.
207 //--
208 bool CMICmnLLDBDebugger::SetDriver( const CMIDriverBase & vClientDriver )
209 {
210         m_pClientDriver = const_cast< CMIDriverBase * >( &vClientDriver );
211
212         return MIstatus::success;
213 }
214
215 //++ ------------------------------------------------------------------------------------
216 // Details:     Get the client driver that is use *this LLDB debugger.
217 // Type:        Method.
218 // Args:        vClientDriver   - (R) A driver.
219 // Return:      CMIDriverBase & - A driver instance.
220 // Throws:      None.
221 //--
222 CMIDriverBase & CMICmnLLDBDebugger::GetDriver( void ) const
223 {
224         return *m_pClientDriver;
225 }
226         
227 //++ ------------------------------------------------------------------------------------
228 // Details:     Initialize the LLDB Debugger object.
229 // Type:        Method.
230 // Args:        None.
231 // Return:      MIstatus::success - Functionality succeeded.
232 //                      MIstatus::failure - Functionality failed.
233 // Throws:      None.
234 //--
235 bool CMICmnLLDBDebugger::InitSBDebugger( void )
236 {
237         m_lldbDebugger = lldb::SBDebugger::Create( false );
238         if( m_lldbDebugger.IsValid() )
239                 return MIstatus::success;
240
241         SetErrorDescription( MIRSRC( IDS_LLDBDEBUGGER_ERR_INVALIDDEBUGGER ) );
242         return MIstatus::failure;
243 }
244
245 //++ ------------------------------------------------------------------------------------
246 // Details:     Set the LLDB Debugger's std in, err and out streams. (Not implemented left 
247 //                      here for reference. Was called in the CMICmnLLDBDebugger::Initialize() )
248 // Type:        Method.
249 // Args:        None.
250 // Return:      MIstatus::success - Functionality succeeded.
251 //                      MIstatus::failure - Functionality failed.
252 // Throws:      None.
253 //--
254 bool CMICmnLLDBDebugger::InitStdStreams( void )
255 {
256         // This is not required when operating the MI driver's code as it has its own
257         // streams. Setting the Stdin for the lldbDebugger especially on LINUX will cause
258         // another thread to run and partially consume stdin data meant for MI stdin handler
259         //m_lldbDebugger.SetErrorFileHandle( m_pClientDriver->GetStderr(), false );     
260         //m_lldbDebugger.SetOutputFileHandle( m_pClientDriver->GetStdout(), false );    
261         //m_lldbDebugger.SetInputFileHandle( m_pClientDriver->GetStdin(), false );
262
263         return MIstatus::success;
264 }
265
266 //++ ------------------------------------------------------------------------------------
267 // Details: Set up the events from the SBDebugger's we would to listent to.
268 // Type:        Method.
269 // Args:        None.
270 // Return:      MIstatus::success - Functionality succeeded.
271 //                      MIstatus::failure - Functionality failed.
272 // Throws:      None.
273 //--
274 bool CMICmnLLDBDebugger::InitSBListener( void )
275 {
276         m_lldbListener = m_lldbDebugger.GetListener();
277         if( !m_lldbListener.IsValid() )
278         {
279                 SetErrorDescription( MIRSRC( IDS_LLDBDEBUGGER_ERR_INVALIDLISTENER ) );
280                 return MIstatus::failure;
281         }
282         
283         const CMIUtilString strDbgId( "CMICmnLLDBDebugger1" );
284         MIuint eventMask = lldb::SBTarget::eBroadcastBitBreakpointChanged;
285         bool bOk = RegisterForEvent( strDbgId, CMIUtilString( lldb::SBTarget::GetBroadcasterClassName() ), eventMask );
286
287         eventMask =     lldb::SBThread::eBroadcastBitStackChanged;
288         bOk = bOk && RegisterForEvent( strDbgId, CMIUtilString( lldb::SBThread::GetBroadcasterClassName() ), eventMask );
289
290         eventMask = lldb::SBProcess::eBroadcastBitStateChanged |
291                                 lldb::SBProcess::eBroadcastBitInterrupt |       
292                                 lldb::SBProcess::eBroadcastBitSTDOUT |
293                                 lldb::SBProcess::eBroadcastBitSTDERR |
294                                 lldb::SBProcess::eBroadcastBitProfileData;
295         bOk = bOk && RegisterForEvent( strDbgId, CMIUtilString( lldb::SBProcess::GetBroadcasterClassName() ), eventMask );
296
297         eventMask = lldb::SBCommandInterpreter::eBroadcastBitQuitCommandReceived |
298                 lldb::SBCommandInterpreter::eBroadcastBitThreadShouldExit |
299                                 lldb::SBCommandInterpreter::eBroadcastBitAsynchronousOutputData |
300                                 lldb::SBCommandInterpreter::eBroadcastBitAsynchronousErrorData;
301         bOk = bOk && RegisterForEvent( strDbgId, CMIUtilString( lldb::SBCommandInterpreter::GetBroadcasterClass() ), eventMask );
302         
303         return bOk;
304 }
305
306 //++ ------------------------------------------------------------------------------------
307 // Details:     Register with the debugger, the SBListener, the type of events you are interested
308 //                      in. Others, like commands, may have already set the mask.
309 // Type:        Method.
310 // Args:        vClientName                     - (R) ID of the client who wants these events set.
311 //                      vBroadcasterClass       - (R) The SBBroadcaster's class name.
312 //                      vEventMask                      - (R) The mask of events to listen for.
313 // Return:      MIstatus::success - Functionality succeeded.
314 //                      MIstatus::failure - Functionality failed.
315 // Throws:      None.
316 //--
317 bool CMICmnLLDBDebugger::RegisterForEvent( const CMIUtilString & vClientName, const CMIUtilString & vBroadcasterClass, const MIuint vEventMask )
318 {
319         MIuint existingMask = 0;
320         if( !BroadcasterGetMask( vBroadcasterClass, existingMask ) )
321                 return MIstatus::failure;
322         
323         if( !ClientSaveMask( vClientName, vBroadcasterClass, vEventMask ) )
324                 return MIstatus::failure;
325
326         const MIchar * pBroadCasterName = vBroadcasterClass.c_str();
327         MIuint eventMask = vEventMask;
328         eventMask += existingMask;
329         const MIuint result = m_lldbListener.StartListeningForEventClass( m_lldbDebugger, pBroadCasterName, eventMask );
330         if( result == 0 )
331         {
332                 SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_STARTLISTENER ), pBroadCasterName ) );
333                 return MIstatus::failure;
334         }
335
336         return BroadcasterSaveMask( vBroadcasterClass, eventMask );
337 }
338
339 //++ ------------------------------------------------------------------------------------
340 // Details:     Register with the debugger, the SBListener, the type of events you are interested
341 //                      in. Others, like commands, may have already set the mask.
342 // Type:        Method.
343 // Args:        vClientName             - (R) ID of the client who wants these events set.
344 //                      vBroadcaster    - (R) An SBBroadcaster's derived class.
345 //                      vEventMask              - (R) The mask of events to listen for.
346 // Return:      MIstatus::success - Functionality succeeded.
347 //                      MIstatus::failure - Functionality failed.
348 // Throws:      None.
349 //--
350 bool CMICmnLLDBDebugger::RegisterForEvent( const CMIUtilString & vClientName, const lldb::SBBroadcaster & vBroadcaster, const MIuint vEventMask )
351 {
352         const MIchar * pBroadcasterName = vBroadcaster.GetName();
353         if( pBroadcasterName == nullptr )
354         {
355                 SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_BROARDCASTER_NAME ), MIRSRC( IDS_WORD_INVALIDNULLPTR ) ) );
356                 return MIstatus::failure;
357         }
358         CMIUtilString broadcasterName( pBroadcasterName );
359         if( broadcasterName.length() == 0 )
360         {
361                 SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_BROARDCASTER_NAME ), MIRSRC( IDS_WORD_INVALIDEMPTY ) ) );
362                 return MIstatus::failure;
363         }
364
365         MIuint existingMask = 0;
366         if( !BroadcasterGetMask( broadcasterName, existingMask ) )
367                 return MIstatus::failure;
368         
369         if( !ClientSaveMask( vClientName, broadcasterName, vEventMask ) )
370                 return MIstatus::failure;
371
372         MIuint eventMask = vEventMask;
373         eventMask += existingMask;
374         const MIuint result = m_lldbListener.StartListeningForEvents( vBroadcaster, eventMask );
375         if( result == 0 )
376         {
377                 SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_STARTLISTENER ), pBroadcasterName ) );
378                 return MIstatus::failure;
379         }
380
381         return BroadcasterSaveMask( broadcasterName, eventMask );
382 }
383
384 //++ ------------------------------------------------------------------------------------
385 // Details:     Unregister with the debugger, the SBListener, the type of events you are no
386 //                      longer interested in. Others, like commands, may still remain interested so 
387 //                      an event may not necessarily be stopped.
388 // Type:        Method.
389 // Args:        vClientName                     - (R) ID of the client who no longer requires these events.
390 //                      vBroadcasterClass       - (R) The SBBroadcaster's class name.
391 // Return:      MIstatus::success - Functionality succeeded.
392 //                      MIstatus::failure - Functionality failed.
393 // Throws:      None.
394 //--
395 bool CMICmnLLDBDebugger::UnregisterForEvent( const CMIUtilString & vClientName, const CMIUtilString & vBroadcasterClass )
396 {
397         MIuint clientsEventMask = 0;
398         if( !ClientGetTheirMask( vClientName, vBroadcasterClass, clientsEventMask ) )
399                 return MIstatus::failure;
400         if( !ClientRemoveTheirMask( vClientName, vBroadcasterClass ) )
401                 return MIstatus::failure;
402         
403         const MIuint otherClientsEventMask = ClientGetMaskForAllClients( vBroadcasterClass );
404         MIuint newEventMask = 0;
405         for( MIuint i = 0; i < 32; i++ )
406         {
407                 const MIuint bit = 1 << i;
408                 const MIuint clientBit = bit & clientsEventMask;
409                 const MIuint othersBit = bit & otherClientsEventMask;
410                 if( (clientBit != 0) && (othersBit == 0) )
411                 {
412                         newEventMask += clientBit;
413                 }
414         }
415         
416         const MIchar * pBroadCasterName = vBroadcasterClass.c_str();
417         if( !m_lldbListener.StopListeningForEventClass( m_lldbDebugger, pBroadCasterName, newEventMask ) )
418         {
419                 SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_STOPLISTENER ), vClientName.c_str(), pBroadCasterName ) );
420                 return MIstatus::failure;
421         }
422
423         return BroadcasterSaveMask( vBroadcasterClass, otherClientsEventMask );
424 }
425
426 //++ ------------------------------------------------------------------------------------
427 // Details:     Given the SBBroadcaster class name retrieve it's current event mask.
428 // Type:        Method.
429 // Args:        vBroadcasterClass       - (R) The SBBroadcaster's class name.
430 //                      vEventMask                      - (W) The mask of events to listen for.
431 // Return:      MIstatus::success - Functionality succeeded.
432 //                      MIstatus::failure - Functionality failed.
433 // Throws:      None.
434 //--
435 bool CMICmnLLDBDebugger::BroadcasterGetMask( const CMIUtilString & vBroadcasterClass, MIuint & vwEventMask ) const
436 {
437         vwEventMask = 0;
438
439         if( vBroadcasterClass.empty() )
440         {
441                 SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_INVALIDBROADCASTER ), vBroadcasterClass.c_str() ) );
442                 return MIstatus::failure;
443         }
444
445         const MapBroadcastClassNameToEventMask_t::const_iterator it = m_mapBroadcastClassNameToEventMask.find( vBroadcasterClass );
446         if( it != m_mapBroadcastClassNameToEventMask.end() )
447         {
448                 vwEventMask = (*it).second;
449         }
450
451         return MIstatus::success;
452 }
453
454 //++ ------------------------------------------------------------------------------------
455 // Details:     Remove the event mask for the specified SBBroadcaster class name.
456 // Type:        Method.
457 // Args:        vBroadcasterClass       - (R) The SBBroadcaster's class name.
458 // Return:      MIstatus::success - Functionality succeeded.
459 //                      MIstatus::failure - Functionality failed.
460 // Throws:      None.
461 //--
462 bool CMICmnLLDBDebugger::BroadcasterRemoveMask( const CMIUtilString & vBroadcasterClass )
463 {
464         MapBroadcastClassNameToEventMask_t::const_iterator it = m_mapBroadcastClassNameToEventMask.find( vBroadcasterClass );
465         if( it != m_mapBroadcastClassNameToEventMask.end() )
466         {
467                 m_mapBroadcastClassNameToEventMask.erase( it );
468         }
469
470         return MIstatus::success;
471 }
472
473 //++ ------------------------------------------------------------------------------------
474 // Details:     Given the SBBroadcaster class name save it's current event mask.
475 // Type:        Method.
476 // Args:        vBroadcasterClass       - (R) The SBBroadcaster's class name.
477 //                      vEventMask                      - (R) The mask of events to listen for.
478 // Return:      MIstatus::success - Functionality succeeded.
479 //                      MIstatus::failure - Functionality failed.
480 // Throws:      None.
481 //--
482 bool CMICmnLLDBDebugger::BroadcasterSaveMask( const CMIUtilString & vBroadcasterClass, const MIuint vEventMask ) 
483 {
484         if( vBroadcasterClass.empty() )
485         {
486                 SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_INVALIDBROADCASTER ), vBroadcasterClass.c_str() ) );
487                 return MIstatus::failure;
488         }
489
490         BroadcasterRemoveMask( vBroadcasterClass );
491         MapPairBroadcastClassNameToEventMask_t pr( vBroadcasterClass, vEventMask );
492         m_mapBroadcastClassNameToEventMask.insert( pr );
493
494         return MIstatus::success;
495 }
496
497 //++ ------------------------------------------------------------------------------------
498 // Details:     Iterate all the clients who have registered event masks against particular
499 //                      SBBroadcasters and build up the mask that is for all of them.
500 // Type:        Method.
501 // Args:        vBroadcasterClass       - (R) The broadcaster to retrieve the mask for.
502 // Return:      MIuint - Event mask.
503 // Throws:      None.
504 //--
505 MIuint CMICmnLLDBDebugger::ClientGetMaskForAllClients( const CMIUtilString & vBroadcasterClass ) const
506 {
507         MIuint mask = 0;
508         MapIdToEventMask_t::const_iterator it = m_mapIdToEventMask.begin();
509         while( it != m_mapIdToEventMask.end() )
510         {
511                 const CMIUtilString & rId( (*it).first );
512                 if( rId.find( vBroadcasterClass.c_str() ) != std::string::npos )
513                 {
514                         const MIuint clientsMask = (*it).second;
515                         mask |= clientsMask;
516                 }
517
518                 // Next
519                 ++it;
520         }
521
522         return mask;
523 }
524
525 //++ ------------------------------------------------------------------------------------
526 // Details:     Given the client save its particular event requirements.
527 // Type:        Method.
528 // Args:        vClientName                     - (R) The Client's unique ID.
529 //                      vBroadcasterClass       - (R) The SBBroadcaster's class name targeted for the events.
530 //                      vEventMask                      - (R) The mask of events to listen for.
531 // Return:      MIstatus::success - Functionality succeeded.
532 //                      MIstatus::failure - Functionality failed.
533 // Throws:      None.
534 //--
535 bool CMICmnLLDBDebugger::ClientSaveMask( const CMIUtilString & vClientName, const CMIUtilString & vBroadcasterClass, const MIuint vEventMask )
536 {
537         if( vClientName.empty() )
538         {
539                 SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_INVALIDCLIENTNAME ), vClientName.c_str() ) );
540                 return MIstatus::failure;
541         }
542
543         CMIUtilString strId( vBroadcasterClass );
544         strId += vClientName;
545
546         ClientRemoveTheirMask( vClientName, vBroadcasterClass );
547         MapPairIdToEventMask_t pr( strId, vEventMask );
548         m_mapIdToEventMask.insert( pr );
549
550         return MIstatus::success;
551 }
552
553 //++ ------------------------------------------------------------------------------------
554 // Details:     Given the client remove it's particular event requirements.
555 // Type:        Method.
556 // Args:        vClientName                     - (R) The Client's unique ID.
557 //                      vBroadcasterClass       - (R) The SBBroadcaster's class name.
558 // Return:      MIstatus::success - Functionality succeeded.
559 //                      MIstatus::failure - Functionality failed.
560 // Throws:      None.
561 //--
562 bool CMICmnLLDBDebugger::ClientRemoveTheirMask( const CMIUtilString & vClientName, const CMIUtilString & vBroadcasterClass )
563 {
564         if( vClientName.empty() )
565         {
566                 SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_INVALIDCLIENTNAME ), vClientName.c_str() ) );
567                 return MIstatus::failure;
568         }
569
570         CMIUtilString strId( vBroadcasterClass );
571         strId += vClientName;
572
573         const MapIdToEventMask_t::const_iterator it = m_mapIdToEventMask.find( strId );
574         if( it != m_mapIdToEventMask.end() )
575         {
576                 m_mapIdToEventMask.erase( it );
577         }
578
579         return MIstatus::success;
580 }
581
582 //++ ------------------------------------------------------------------------------------
583 // Details:     Retrieve the client's event mask used for on a particular SBBroadcaster.
584 // Type:        Method.
585 // Args:        vClientName                     - (R) The Client's unique ID.
586 //                      vBroadcasterClass       - (R) The SBBroadcaster's class name.
587 //                      vwEventMask                     - (W) The client's mask.
588 // Return:      MIstatus::success - Functionality succeeded.
589 //                      MIstatus::failure - Functionality failed.
590 // Throws:      None.
591 //--
592 bool CMICmnLLDBDebugger::ClientGetTheirMask( const CMIUtilString & vClientName, const CMIUtilString & vBroadcasterClass, MIuint & vwEventMask )
593 {
594         vwEventMask = 0;
595
596         if( vClientName.empty() )
597         {
598                 SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_INVALIDCLIENTNAME ), vClientName.c_str() ) );
599                 return MIstatus::failure;
600         }
601
602         CMIUtilString strId( vBroadcasterClass.c_str() );
603         strId += vClientName;
604
605         const MapIdToEventMask_t::const_iterator it = m_mapIdToEventMask.find( strId );
606         if( it != m_mapIdToEventMask.end() )
607         {
608                 vwEventMask = (*it).second;
609         }
610
611         SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_CLIENTNOTREGISTERD ), vClientName.c_str() ) );
612
613         return MIstatus::failure;
614 }
615
616 //++ ------------------------------------------------------------------------------------
617 // Details:     Momentarily wait for an events being broadcast and inspect those that do
618 //                      come this way. Check if the target should exit event if so start shutting
619 //                      down this thread and the application. Any other events pass on to the 
620 //                      Out-of-band handler to futher determine what kind of event arrived.
621 //                      This function runs in the thread "MI debugger event".
622 // Type:        Method.
623 // Args:        vrbIsAlive      - (W) False = yes exit event monitoring thread, true = continue.
624 // Return:      MIstatus::success - Functional succeeded.
625 //                      MIstatus::failure - Functional failed.
626 // Throws:      None.
627 //--
628 bool CMICmnLLDBDebugger::MonitorSBListenerEvents( bool & vrbIsAlive )
629 {
630         vrbIsAlive = true;
631
632         lldb::SBEvent event;
633         const bool bGotEvent = m_lldbListener.GetNextEvent( event );
634         if ( !bGotEvent || !event.IsValid() )
635         {
636                 const std::chrono::milliseconds time( 1 );
637                 std::this_thread::sleep_for( time );
638                 return MIstatus::success;
639         }
640         if( !event.GetBroadcaster().IsValid() )
641                 return MIstatus::success;
642
643         // Debugging
644         m_pLog->WriteLog( CMIUtilString::Format( "##### An event occurred: %s", event.GetBroadcasterClass() ) );
645
646         bool bHandledEvent = false;
647         bool bExitAppEvent = false;
648         const bool bOk = CMICmnLLDBDebuggerHandleEvents::Instance().HandleEvent( event, bHandledEvent, bExitAppEvent );
649         if( !bHandledEvent )
650         {
651                 const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_WRN_UNKNOWN_EVENT ), event.GetBroadcasterClass() ) );
652                 m_pLog->WriteLog( msg );
653         }
654         if( !bOk )
655         {
656                 m_pLog->WriteLog( CMICmnLLDBDebuggerHandleEvents::Instance().GetErrorDescription() );
657         }
658         
659         if( bExitAppEvent )
660         {
661                 // Set the application to shutdown
662                 m_pClientDriver->SetExitApplicationFlag( true );
663
664                 // Kill *this thread
665                 vrbIsAlive = false;
666         }
667
668         return bOk;
669 }
670
671 //++ ------------------------------------------------------------------------------------
672 // Details:     The main worker method for this thread.
673 // Type:        Method.
674 // Args:        vrbIsAlive      = (W) True = *this thread is working, false = thread has exited.                        
675 // Return:      MIstatus::success - Functional succeeded.
676 //                      MIstatus::failure - Functional failed.
677 // Throws:      None.
678 //--
679 bool CMICmnLLDBDebugger::ThreadRun( bool & vrbIsAlive )
680 {
681         return MonitorSBListenerEvents( vrbIsAlive );
682 }
683
684 //++ ------------------------------------------------------------------------------------
685 // Details:     Let this thread clean up after itself.
686 // Type:        Method.
687 // Args:        
688 // Return:      MIstatus::success - Functionality succeeded.
689 //                      MIstatus::failure - Functionality failed.
690 // Throws:      None.
691 //--
692 bool CMICmnLLDBDebugger::ThreadFinish( void )
693 {
694         return MIstatus::success;
695 }
696
697 //++ ------------------------------------------------------------------------------------
698 // Details:     Retrieve *this thread object's name.
699 // Type:        Overridden.
700 // Args:        None.                   
701 // Return:      CMIUtilString & - Text.
702 // Throws:      None.
703 //--
704 const CMIUtilString & CMICmnLLDBDebugger::ThreadGetName( void ) const
705 {
706         return m_constStrThisThreadId;
707 }