aboutsummaryrefslogblamecommitdiff
path: root/tools/lldb-mi/MICmnLLDBDebugger.cpp
blob: 273b805156f4d992d6f1beb01b038ef56304bb7c (plain) (tree)
1
2
3
4
5
6
7
8
9
10









                                                                                
                                     
  
                                                  
  


                                                                     
  
                     



                              
                              













                                                                                         




                                           
    

                                                 



                                                                                         




                                          
    
                                             
 
               


                                                                                         





                                                           
    

                                    
 

















































                                                                                                                


                                                                                         





                                                        
    

                                  
 









































                                                                                                      

                                                                                         




                                                                             
    

                                        
 
                          


                                                                                         




                                                                             
    

                                        
 
                          


                                                                                         






                                                                                           
    

                                                                 
 
                                                                  
 
                             


                                                                                         




                                                                  
    

                                         
 
                            
 
 
                                                                                         





                                                        
    

                                        
 


                                                     
 

                                                                      


                                                                                         






                                                                                      
    

                                        
 







                                                                                        



                                                                                         




                                                        
    

                                        
 























                                                                                                                                          


                                                                                         








                                                                                             
    

                                                                                                                                       
 

















                                                                                                                  


                                                                                         








                                                                                             
    

                                                                                                                                        
 





























                                                                                                                                    


                                                                                         








                                                                                           
    

                                                                                                                
 


























                                                                                                                                     


                                                                                         






                                                                                
    

                                                                                                         
 
                    
 




                                                                                                                               
 




                                                                                                                             
 
                             


                                                                                         





                                                                             
    

                                                                                 
 




                                                                                                                       
 
                             


                                                                                         






                                                                            
    

                                                                                                        
 




                                                                                                                               
 


                                                                             
 
                             


                                                                                         





                                                                                      
    

                                                                                            
 















                                                                       


                                                                                         







                                                                                           
    

                                                                                                                                     
 




                                                                                                                        
 

                                           
 


                                                          
 
                             


                                                                                         






                                                                       
    

                                                                                                                   
 















                                                                                                                        


                                                                                         







                                                                                    
    

                                                                                                                                     
 
                    
 




                                                                                                                        
 

                                                   
 




                                                                                 
 
                                                                                                                     
 
                             


                                                                                         









                                                                                        
    

                                                             
 






































                                                                                                                                


                                                                                         





                                                                                        
    

                                               
 
                                               


                                                                                         





                                                        
    

                                      
 
                             


                                                                                         




                                                
    

                                             
 
                                  
 
//===-- MICmnLLDBDebugger.cpp -----------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

//++
// File:        MICmnLLDBDebugger.cpp
//
// Overview:    CMICmnLLDBDebugger implementation.
//
// Environment: Compilers:  Visual C++ 12.
//                          gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
//              Libraries:  See MIReadmetxt.
//
// Copyright:   None.
//--

// Third party headers:
#include <lldb/API/SBTarget.h>
#include <lldb/API/SBThread.h>
#include <lldb/API/SBProcess.h>
#include <lldb/API/SBCommandInterpreter.h>

// In-house headers:
#include "MICmnLLDBDebugger.h"
#include "MICmnResources.h"
#include "MICmnLog.h"
#include "MIDriverBase.h"
#include "MICmnThreadMgrStd.h"
#include "MICmnLLDBDebuggerHandleEvents.h"
#include "MICmnLLDBDebugSessionInfo.h"
#include "MIUtilSingletonHelper.h"

//++ ------------------------------------------------------------------------------------
// Details: CMICmnLLDBDebugger constructor.
// Type:    Method.
// Args:    None.
// Return:  None.
// Throws:  None.
//--
CMICmnLLDBDebugger::CMICmnLLDBDebugger(void)
    : m_constStrThisThreadId("MI debugger event")
{
}

//++ ------------------------------------------------------------------------------------
// Details: CMICmnLLDBDebugger destructor.
// Type:    Overridable.
// Args:    None.
// Return:  None.
// Throws:  None.
//--
CMICmnLLDBDebugger::~CMICmnLLDBDebugger(void)
{
    Shutdown();
}

//++ ------------------------------------------------------------------------------------
// Details: Initialize resources for *this debugger object.
// Type:    Method.
// Args:    None.
// Return:  MIstatus::success - Functionality succeeded.
//          MIstatus::failure - Functionality failed.
// Throws:  None.
//--
bool
CMICmnLLDBDebugger::Initialize(void)
{
    m_clientUsageRefCnt++;

    if (m_bInitialized)
        return MIstatus::success;

    bool bOk = MIstatus::success;
    CMIUtilString errMsg;
    ClrErrorDescription();

    if (m_pClientDriver == nullptr)
    {
        bOk = false;
        errMsg = MIRSRC(IDS_LLDBDEBUGGER_ERR_CLIENTDRIVER);
    }

    // Note initialization order is important here as some resources depend on previous
    MI::ModuleInit<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg);
    MI::ModuleInit<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg);
    MI::ModuleInit<CMICmnThreadMgrStd>(IDS_MI_INIT_ERR_THREADMGR, bOk, errMsg);
    MI::ModuleInit<CMICmnLLDBDebuggerHandleEvents>(IDS_MI_INIT_ERR_OUTOFBANDHANDLER, bOk, errMsg);
    MI::ModuleInit<CMICmnLLDBDebugSessionInfo>(IDS_MI_INIT_ERR_DEBUGSESSIONINFO, bOk, errMsg);

    // Note order is important here!
    if (bOk)
        lldb::SBDebugger::Initialize();
    if (bOk && !InitSBDebugger())
    {
        bOk = false;
        if (!errMsg.empty())
            errMsg += ", ";
        errMsg += GetErrorDescription().c_str();
    }
    if (bOk && !InitSBListener())
    {
        bOk = false;
        if (!errMsg.empty())
            errMsg += ", ";
        errMsg += GetErrorDescription().c_str();
    }
    bOk = bOk && InitStdStreams();

    m_bInitialized = bOk;

    if (!bOk && !HaveErrorDescription())
    {
        CMIUtilString strInitError(CMIUtilString::Format(MIRSRC(IDS_MI_INIT_ERR_LLDBDEBUGGER), errMsg.c_str()));
        SetErrorDescription(strInitError);
    }

    return bOk;
}

//++ ------------------------------------------------------------------------------------
// Details: Release resources for *this debugger object.
// Type:    Method.
// Args:    None.
// Return:  MIstatus::success - Functionality succeeded.
//          MIstatus::failure - Functionality failed.
// Throws:  None.
//--
bool
CMICmnLLDBDebugger::Shutdown(void)
{
    if (--m_clientUsageRefCnt > 0)
        return MIstatus::success;

    if (!m_bInitialized)
        return MIstatus::success;

    m_bInitialized = false;

    ClrErrorDescription();

    bool bOk = MIstatus::success;
    CMIUtilString errMsg;

    // Explicitly delete the remote target in case MI needs to exit prematurely otherwise
    // LLDB debugger may hang in its Destroy() fn waiting on events
    m_lldbDebugger.DeleteTarget(CMICmnLLDBDebugSessionInfo::Instance().m_lldbTarget);

    // Debug: May need this but does seem to work without it so commented out the fudge 19/06/2014
    // It appears we need to wait as hang does not occur when hitting a debug breakpoint here
    // const std::chrono::milliseconds time( 1000 );
    // std::this_thread::sleep_for( time );

    lldb::SBDebugger::Destroy(m_lldbDebugger);
    lldb::SBDebugger::Terminate();
    m_pClientDriver = nullptr;
    m_mapBroadcastClassNameToEventMask.clear();
    m_mapIdToEventMask.clear();

    // Note shutdown order is important here
    MI::ModuleShutdown<CMICmnLLDBDebugSessionInfo>(IDS_MI_INIT_ERR_DEBUGSESSIONINFO, bOk, errMsg);
    MI::ModuleShutdown<CMICmnLLDBDebuggerHandleEvents>(IDS_MI_INIT_ERR_OUTOFBANDHANDLER, bOk, errMsg);
    MI::ModuleShutdown<CMICmnThreadMgrStd>(IDS_MI_INIT_ERR_THREADMGR, bOk, errMsg);
    MI::ModuleShutdown<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg);
    MI::ModuleShutdown<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg);

    if (!bOk)
    {
        SetErrorDescriptionn(MIRSRC(IDS_MI_SHTDWN_ERR_LLDBDEBUGGER), errMsg.c_str());
    }

    return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details: Return the LLDB debugger instance created for this debug session.
// Type:    Method.
// Args:    None.
// Return:  lldb::SBDebugger & - LLDB debugger object reference.
// Throws:  None.
//--
lldb::SBDebugger &
CMICmnLLDBDebugger::GetTheDebugger(void)
{
    return m_lldbDebugger;
}

//++ ------------------------------------------------------------------------------------
// Details: Return the LLDB listener instance created for this debug session.
// Type:    Method.
// Args:    None.
// Return:  lldb::SBListener & - LLDB listener object reference.
// Throws:  None.
//--
lldb::SBListener &
CMICmnLLDBDebugger::GetTheListener(void)
{
    return m_lldbListener;
}

//++ ------------------------------------------------------------------------------------
// Details: Set the client driver that wants to use *this LLDB debugger. Call this function
//          prior to Initialize().
// Type:    Method.
// Args:    vClientDriver   - (R) A driver.
// Return:  MIstatus::success - Functionality succeeded.
//          MIstatus::failure - Functionality failed.
// Throws:  None.
//--
bool
CMICmnLLDBDebugger::SetDriver(const CMIDriverBase &vClientDriver)
{
    m_pClientDriver = const_cast<CMIDriverBase *>(&vClientDriver);

    return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details: Get the client driver that is use *this LLDB debugger.
// Type:    Method.
// Args:    vClientDriver   - (R) A driver.
// Return:  CMIDriverBase & - A driver instance.
// Throws:  None.
//--
CMIDriverBase &
CMICmnLLDBDebugger::GetDriver(void) const
{
    return *m_pClientDriver;
}

//++ ------------------------------------------------------------------------------------
// Details: Initialize the LLDB Debugger object.
// Type:    Method.
// Args:    None.
// Return:  MIstatus::success - Functionality succeeded.
//          MIstatus::failure - Functionality failed.
// Throws:  None.
//--
bool
CMICmnLLDBDebugger::InitSBDebugger(void)
{
    m_lldbDebugger = lldb::SBDebugger::Create(false);
    if (m_lldbDebugger.IsValid())
        return MIstatus::success;

    SetErrorDescription(MIRSRC(IDS_LLDBDEBUGGER_ERR_INVALIDDEBUGGER));
    return MIstatus::failure;
}

//++ ------------------------------------------------------------------------------------
// Details: Set the LLDB Debugger's std in, err and out streams. (Not implemented left
//          here for reference. Was called in the CMICmnLLDBDebugger::Initialize() )
// Type:    Method.
// Args:    None.
// Return:  MIstatus::success - Functionality succeeded.
//          MIstatus::failure - Functionality failed.
// Throws:  None.
//--
bool
CMICmnLLDBDebugger::InitStdStreams(void)
{
    // This is not required when operating the MI driver's code as it has its own
    // streams. Setting the Stdin for the lldbDebugger especially on LINUX will cause
    // another thread to run and partially consume stdin data meant for MI stdin handler
    // m_lldbDebugger.SetErrorFileHandle( m_pClientDriver->GetStderr(), false );
    // m_lldbDebugger.SetOutputFileHandle( m_pClientDriver->GetStdout(), false );
    // m_lldbDebugger.SetInputFileHandle( m_pClientDriver->GetStdin(), false );

    return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details: Set up the events from the SBDebugger's we would to listent to.
// Type:    Method.
// Args:    None.
// Return:  MIstatus::success - Functionality succeeded.
//          MIstatus::failure - Functionality failed.
// Throws:  None.
//--
bool
CMICmnLLDBDebugger::InitSBListener(void)
{
    m_lldbListener = m_lldbDebugger.GetListener();
    if (!m_lldbListener.IsValid())
    {
        SetErrorDescription(MIRSRC(IDS_LLDBDEBUGGER_ERR_INVALIDLISTENER));
        return MIstatus::failure;
    }

    const CMIUtilString strDbgId("CMICmnLLDBDebugger1");
    MIuint eventMask = lldb::SBTarget::eBroadcastBitBreakpointChanged;
    bool bOk = RegisterForEvent(strDbgId, CMIUtilString(lldb::SBTarget::GetBroadcasterClassName()), eventMask);

    eventMask = lldb::SBThread::eBroadcastBitStackChanged;
    bOk = bOk && RegisterForEvent(strDbgId, CMIUtilString(lldb::SBThread::GetBroadcasterClassName()), eventMask);

    eventMask = lldb::SBProcess::eBroadcastBitStateChanged | lldb::SBProcess::eBroadcastBitInterrupt |
                lldb::SBProcess::eBroadcastBitSTDOUT | lldb::SBProcess::eBroadcastBitSTDERR | lldb::SBProcess::eBroadcastBitProfileData;
    bOk = bOk && RegisterForEvent(strDbgId, CMIUtilString(lldb::SBProcess::GetBroadcasterClassName()), eventMask);

    eventMask = lldb::SBCommandInterpreter::eBroadcastBitQuitCommandReceived | lldb::SBCommandInterpreter::eBroadcastBitThreadShouldExit |
                lldb::SBCommandInterpreter::eBroadcastBitAsynchronousOutputData |
                lldb::SBCommandInterpreter::eBroadcastBitAsynchronousErrorData;
    bOk = bOk && RegisterForEvent(strDbgId, CMIUtilString(lldb::SBCommandInterpreter::GetBroadcasterClass()), eventMask);

    return bOk;
}

//++ ------------------------------------------------------------------------------------
// Details: Register with the debugger, the SBListener, the type of events you are interested
//          in. Others, like commands, may have already set the mask.
// Type:    Method.
// Args:    vClientName         - (R) ID of the client who wants these events set.
//          vBroadcasterClass   - (R) The SBBroadcaster's class name.
//          vEventMask          - (R) The mask of events to listen for.
// Return:  MIstatus::success - Functionality succeeded.
//          MIstatus::failure - Functionality failed.
// Throws:  None.
//--
bool
CMICmnLLDBDebugger::RegisterForEvent(const CMIUtilString &vClientName, const CMIUtilString &vBroadcasterClass, const MIuint vEventMask)
{
    MIuint existingMask = 0;
    if (!BroadcasterGetMask(vBroadcasterClass, existingMask))
        return MIstatus::failure;

    if (!ClientSaveMask(vClientName, vBroadcasterClass, vEventMask))
        return MIstatus::failure;

    const MIchar *pBroadCasterName = vBroadcasterClass.c_str();
    MIuint eventMask = vEventMask;
    eventMask += existingMask;
    const MIuint result = m_lldbListener.StartListeningForEventClass(m_lldbDebugger, pBroadCasterName, eventMask);
    if (result == 0)
    {
        SetErrorDescription(CMIUtilString::Format(MIRSRC(IDS_LLDBDEBUGGER_ERR_STARTLISTENER), pBroadCasterName));
        return MIstatus::failure;
    }

    return BroadcasterSaveMask(vBroadcasterClass, eventMask);
}

//++ ------------------------------------------------------------------------------------
// Details: Register with the debugger, the SBListener, the type of events you are interested
//          in. Others, like commands, may have already set the mask.
// Type:    Method.
// Args:    vClientName     - (R) ID of the client who wants these events set.
//          vBroadcaster    - (R) An SBBroadcaster's derived class.
//          vEventMask      - (R) The mask of events to listen for.
// Return:  MIstatus::success - Functionality succeeded.
//          MIstatus::failure - Functionality failed.
// Throws:  None.
//--
bool
CMICmnLLDBDebugger::RegisterForEvent(const CMIUtilString &vClientName, const lldb::SBBroadcaster &vBroadcaster, const MIuint vEventMask)
{
    const MIchar *pBroadcasterName = vBroadcaster.GetName();
    if (pBroadcasterName == nullptr)
    {
        SetErrorDescription(CMIUtilString::Format(MIRSRC(IDS_LLDBDEBUGGER_ERR_BROARDCASTER_NAME), MIRSRC(IDS_WORD_INVALIDNULLPTR)));
        return MIstatus::failure;
    }
    CMIUtilString broadcasterName(pBroadcasterName);
    if (broadcasterName.length() == 0)
    {
        SetErrorDescription(CMIUtilString::Format(MIRSRC(IDS_LLDBDEBUGGER_ERR_BROARDCASTER_NAME), MIRSRC(IDS_WORD_INVALIDEMPTY)));
        return MIstatus::failure;
    }

    MIuint existingMask = 0;
    if (!BroadcasterGetMask(broadcasterName, existingMask))
        return MIstatus::failure;

    if (!ClientSaveMask(vClientName, broadcasterName, vEventMask))
        return MIstatus::failure;

    MIuint eventMask = vEventMask;
    eventMask += existingMask;
    const MIuint result = m_lldbListener.StartListeningForEvents(vBroadcaster, eventMask);
    if (result == 0)
    {
        SetErrorDescription(CMIUtilString::Format(MIRSRC(IDS_LLDBDEBUGGER_ERR_STARTLISTENER), pBroadcasterName));
        return MIstatus::failure;
    }

    return BroadcasterSaveMask(broadcasterName, eventMask);
}

//++ ------------------------------------------------------------------------------------
// Details: Unregister with the debugger, the SBListener, the type of events you are no
//          longer interested in. Others, like commands, may still remain interested so
//          an event may not necessarily be stopped.
// Type:    Method.
// Args:    vClientName         - (R) ID of the client who no longer requires these events.
//          vBroadcasterClass   - (R) The SBBroadcaster's class name.
// Return:  MIstatus::success - Functionality succeeded.
//          MIstatus::failure - Functionality failed.
// Throws:  None.
//--
bool
CMICmnLLDBDebugger::UnregisterForEvent(const CMIUtilString &vClientName, const CMIUtilString &vBroadcasterClass)
{
    MIuint clientsEventMask = 0;
    if (!ClientGetTheirMask(vClientName, vBroadcasterClass, clientsEventMask))
        return MIstatus::failure;
    if (!ClientRemoveTheirMask(vClientName, vBroadcasterClass))
        return MIstatus::failure;

    const MIuint otherClientsEventMask = ClientGetMaskForAllClients(vBroadcasterClass);
    MIuint newEventMask = 0;
    for (MIuint i = 0; i < 32; i++)
    {
        const MIuint bit = 1 << i;
        const MIuint clientBit = bit & clientsEventMask;
        const MIuint othersBit = bit & otherClientsEventMask;
        if ((clientBit != 0) && (othersBit == 0))
        {
            newEventMask += clientBit;
        }
    }

    const MIchar *pBroadCasterName = vBroadcasterClass.c_str();
    if (!m_lldbListener.StopListeningForEventClass(m_lldbDebugger, pBroadCasterName, newEventMask))
    {
        SetErrorDescription(CMIUtilString::Format(MIRSRC(IDS_LLDBDEBUGGER_ERR_STOPLISTENER), vClientName.c_str(), pBroadCasterName));
        return MIstatus::failure;
    }

    return BroadcasterSaveMask(vBroadcasterClass, otherClientsEventMask);
}

//++ ------------------------------------------------------------------------------------
// Details: Given the SBBroadcaster class name retrieve it's current event mask.
// Type:    Method.
// Args:    vBroadcasterClass   - (R) The SBBroadcaster's class name.
//          vEventMask          - (W) The mask of events to listen for.
// Return:  MIstatus::success - Functionality succeeded.
//          MIstatus::failure - Functionality failed.
// Throws:  None.
//--
bool
CMICmnLLDBDebugger::BroadcasterGetMask(const CMIUtilString &vBroadcasterClass, MIuint &vwEventMask) const
{
    vwEventMask = 0;

    if (vBroadcasterClass.empty())
    {
        SetErrorDescription(CMIUtilString::Format(MIRSRC(IDS_LLDBDEBUGGER_ERR_INVALIDBROADCASTER), vBroadcasterClass.c_str()));
        return MIstatus::failure;
    }

    const MapBroadcastClassNameToEventMask_t::const_iterator it = m_mapBroadcastClassNameToEventMask.find(vBroadcasterClass);
    if (it != m_mapBroadcastClassNameToEventMask.end())
    {
        vwEventMask = (*it).second;
    }

    return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details: Remove the event mask for the specified SBBroadcaster class name.
// Type:    Method.
// Args:    vBroadcasterClass - (R) The SBBroadcaster's class name.
// Return:  MIstatus::success - Functionality succeeded.
//          MIstatus::failure - Functionality failed.
// Throws:  None.
//--
bool
CMICmnLLDBDebugger::BroadcasterRemoveMask(const CMIUtilString &vBroadcasterClass)
{
    MapBroadcastClassNameToEventMask_t::const_iterator it = m_mapBroadcastClassNameToEventMask.find(vBroadcasterClass);
    if (it != m_mapBroadcastClassNameToEventMask.end())
    {
        m_mapBroadcastClassNameToEventMask.erase(it);
    }

    return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details: Given the SBBroadcaster class name save it's current event mask.
// Type:    Method.
// Args:    vBroadcasterClass - (R) The SBBroadcaster's class name.
//          vEventMask        - (R) The mask of events to listen for.
// Return:  MIstatus::success - Functionality succeeded.
//          MIstatus::failure - Functionality failed.
// Throws:  None.
//--
bool
CMICmnLLDBDebugger::BroadcasterSaveMask(const CMIUtilString &vBroadcasterClass, const MIuint vEventMask)
{
    if (vBroadcasterClass.empty())
    {
        SetErrorDescription(CMIUtilString::Format(MIRSRC(IDS_LLDBDEBUGGER_ERR_INVALIDBROADCASTER), vBroadcasterClass.c_str()));
        return MIstatus::failure;
    }

    BroadcasterRemoveMask(vBroadcasterClass);
    MapPairBroadcastClassNameToEventMask_t pr(vBroadcasterClass, vEventMask);
    m_mapBroadcastClassNameToEventMask.insert(pr);

    return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details: Iterate all the clients who have registered event masks against particular
//          SBBroadcasters and build up the mask that is for all of them.
// Type:    Method.
// Args:    vBroadcasterClass   - (R) The broadcaster to retrieve the mask for.
// Return:  MIuint - Event mask.
// Throws:  None.
//--
MIuint
CMICmnLLDBDebugger::ClientGetMaskForAllClients(const CMIUtilString &vBroadcasterClass) const
{
    MIuint mask = 0;
    MapIdToEventMask_t::const_iterator it = m_mapIdToEventMask.begin();
    while (it != m_mapIdToEventMask.end())
    {
        const CMIUtilString &rId((*it).first);
        if (rId.find(vBroadcasterClass.c_str()) != std::string::npos)
        {
            const MIuint clientsMask = (*it).second;
            mask |= clientsMask;
        }

        // Next
        ++it;
    }

    return mask;
}

//++ ------------------------------------------------------------------------------------
// Details: Given the client save its particular event requirements.
// Type:    Method.
// Args:    vClientName       - (R) The Client's unique ID.
//          vBroadcasterClass - (R) The SBBroadcaster's class name targeted for the events.
//          vEventMask        - (R) The mask of events to listen for.
// Return:  MIstatus::success - Functionality succeeded.
//          MIstatus::failure - Functionality failed.
// Throws:  None.
//--
bool
CMICmnLLDBDebugger::ClientSaveMask(const CMIUtilString &vClientName, const CMIUtilString &vBroadcasterClass, const MIuint vEventMask)
{
    if (vClientName.empty())
    {
        SetErrorDescription(CMIUtilString::Format(MIRSRC(IDS_LLDBDEBUGGER_ERR_INVALIDCLIENTNAME), vClientName.c_str()));
        return MIstatus::failure;
    }

    CMIUtilString strId(vBroadcasterClass);
    strId += vClientName;

    ClientRemoveTheirMask(vClientName, vBroadcasterClass);
    MapPairIdToEventMask_t pr(strId, vEventMask);
    m_mapIdToEventMask.insert(pr);

    return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details: Given the client remove it's particular event requirements.
// Type:    Method.
// Args:    vClientName       - (R) The Client's unique ID.
//          vBroadcasterClass - (R) The SBBroadcaster's class name.
// Return:  MIstatus::success - Functionality succeeded.
//          MIstatus::failure - Functionality failed.
// Throws:  None.
//--
bool
CMICmnLLDBDebugger::ClientRemoveTheirMask(const CMIUtilString &vClientName, const CMIUtilString &vBroadcasterClass)
{
    if (vClientName.empty())
    {
        SetErrorDescription(CMIUtilString::Format(MIRSRC(IDS_LLDBDEBUGGER_ERR_INVALIDCLIENTNAME), vClientName.c_str()));
        return MIstatus::failure;
    }

    CMIUtilString strId(vBroadcasterClass);
    strId += vClientName;

    const MapIdToEventMask_t::const_iterator it = m_mapIdToEventMask.find(strId);
    if (it != m_mapIdToEventMask.end())
    {
        m_mapIdToEventMask.erase(it);
    }

    return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details: Retrieve the client's event mask used for on a particular SBBroadcaster.
// Type:    Method.
// Args:    vClientName       - (R) The Client's unique ID.
//          vBroadcasterClass - (R) The SBBroadcaster's class name.
//          vwEventMask       - (W) The client's mask.
// Return:  MIstatus::success - Functionality succeeded.
//          MIstatus::failure - Functionality failed.
// Throws:  None.
//--
bool
CMICmnLLDBDebugger::ClientGetTheirMask(const CMIUtilString &vClientName, const CMIUtilString &vBroadcasterClass, MIuint &vwEventMask)
{
    vwEventMask = 0;

    if (vClientName.empty())
    {
        SetErrorDescription(CMIUtilString::Format(MIRSRC(IDS_LLDBDEBUGGER_ERR_INVALIDCLIENTNAME), vClientName.c_str()));
        return MIstatus::failure;
    }

    CMIUtilString strId(vBroadcasterClass.c_str());
    strId += vClientName;

    const MapIdToEventMask_t::const_iterator it = m_mapIdToEventMask.find(strId);
    if (it != m_mapIdToEventMask.end())
    {
        vwEventMask = (*it).second;
    }

    SetErrorDescription(CMIUtilString::Format(MIRSRC(IDS_LLDBDEBUGGER_ERR_CLIENTNOTREGISTERD), vClientName.c_str()));

    return MIstatus::failure;
}

//++ ------------------------------------------------------------------------------------
// Details: Momentarily wait for an events being broadcast and inspect those that do
//          come this way. Check if the target should exit event if so start shutting
//          down this thread and the application. Any other events pass on to the
//          Out-of-band handler to futher determine what kind of event arrived.
//          This function runs in the thread "MI debugger event".
// Type:    Method.
// Args:    vrbIsAlive  - (W) False = yes exit event monitoring thread, true = continue.
// Return:  MIstatus::success - Functional succeeded.
//          MIstatus::failure - Functional failed.
// Throws:  None.
//--
bool
CMICmnLLDBDebugger::MonitorSBListenerEvents(bool &vrbIsAlive)
{
    vrbIsAlive = true;

    lldb::SBEvent event;
    const bool bGotEvent = m_lldbListener.GetNextEvent(event);
    if (!bGotEvent || !event.IsValid())
    {
        const std::chrono::milliseconds time(1);
        std::this_thread::sleep_for(time);
        return MIstatus::success;
    }
    if (!event.GetBroadcaster().IsValid())
        return MIstatus::success;

    // Debugging
    m_pLog->WriteLog(CMIUtilString::Format("##### An event occurred: %s", event.GetBroadcasterClass()));

    bool bHandledEvent = false;
    bool bExitAppEvent = false;
    const bool bOk = CMICmnLLDBDebuggerHandleEvents::Instance().HandleEvent(event, bHandledEvent, bExitAppEvent);
    if (!bHandledEvent)
    {
        const CMIUtilString msg(CMIUtilString::Format(MIRSRC(IDS_LLDBDEBUGGER_WRN_UNKNOWN_EVENT), event.GetBroadcasterClass()));
        m_pLog->WriteLog(msg);
    }
    if (!bOk)
    {
        m_pLog->WriteLog(CMICmnLLDBDebuggerHandleEvents::Instance().GetErrorDescription());
    }

    if (bExitAppEvent)
    {
        // Set the application to shutdown
        m_pClientDriver->SetExitApplicationFlag(true);

        // Kill *this thread
        vrbIsAlive = false;
    }

    return bOk;
}

//++ ------------------------------------------------------------------------------------
// Details: The main worker method for this thread.
// Type:    Method.
// Args:    vrbIsAlive  - (W) True = *this thread is working, false = thread has exited.
// Return:  MIstatus::success - Functional succeeded.
//          MIstatus::failure - Functional failed.
// Throws:  None.
//--
bool
CMICmnLLDBDebugger::ThreadRun(bool &vrbIsAlive)
{
    return MonitorSBListenerEvents(vrbIsAlive);
}

//++ ------------------------------------------------------------------------------------
// Details: Let this thread clean up after itself.
// Type:    Method.
// Args:
// Return:  MIstatus::success - Functionality succeeded.
//          MIstatus::failure - Functionality failed.
// Throws:  None.
//--
bool
CMICmnLLDBDebugger::ThreadFinish(void)
{
    return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details: Retrieve *this thread object's name.
// Type:    Overridden.
// Args:    None.
// Return:  CMIUtilString & - Text.
// Throws:  None.
//--
const CMIUtilString &
CMICmnLLDBDebugger::ThreadGetName(void) const
{
    return m_constStrThisThreadId;
}