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