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