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