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