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 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 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 //-- 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 //-- 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 //-- 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 //-- 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 //-- 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 //-- 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 //-- 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 //-- 268 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 //-- 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 //-- 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 //-- 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 //-- 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 //-- 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 //-- 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 //-- 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 //-- 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 //-- 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 //-- 591 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 //-- 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 //-- 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 //-- 667 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 //-- 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 //-- 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 //-- 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 //-- 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 //-- 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 //-- 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 //-- 883 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 //-- 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 //-- 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