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