diff --git a/lldb/include/lldb/API/SBAttachInfo.h b/lldb/include/lldb/API/SBAttachInfo.h --- a/lldb/include/lldb/API/SBAttachInfo.h +++ b/lldb/include/lldb/API/SBAttachInfo.h @@ -168,6 +168,25 @@ /// allows a different listener to be used to listen for process events. void SetListener(SBListener &listener); + /// Get the shadow listener that receive public process events, + /// additionally to the default process event listener. + /// + /// If no listener has been set via a call to + /// SBLaunchInfo::SetShadowListener(), then an invalid SBListener will + /// be returned (SBListener::IsValid() will return false). If a listener + /// has been set, then the valid listener object will be returned. + SBListener GetShadowListener(); + + /// Set the shadow listener that will receive public process events, + /// additionally to the default process event listener. + /// + /// By default a process have no shadow event listener. + /// Calling this function allows public process events to be broadcasted to an + /// additional listener on top of the default process event listener. + /// If the `listener` argument is invalid (SBListener::IsValid() will + /// return false), this will clear the shadow listener. + void SetShadowListener(SBListener &listener); + const char *GetScriptedProcessClassName() const; void SetScriptedProcessClassName(const char *class_name); diff --git a/lldb/include/lldb/API/SBLaunchInfo.h b/lldb/include/lldb/API/SBLaunchInfo.h --- a/lldb/include/lldb/API/SBLaunchInfo.h +++ b/lldb/include/lldb/API/SBLaunchInfo.h @@ -92,6 +92,25 @@ /// allows a different listener to be used to listen for process events. void SetListener(SBListener &listener); + /// Get the shadow listener that receive public process events, + /// additionally to the default process event listener. + /// + /// If no listener has been set via a call to + /// SBLaunchInfo::SetShadowListener(), then an invalid SBListener will + /// be returned (SBListener::IsValid() will return false). If a listener + /// has been set, then the valid listener object will be returned. + SBListener GetShadowListener(); + + /// Set the shadow listener that will receive public process events, + /// additionally to the default process event listener. + /// + /// By default a process have no shadow event listener. + /// Calling this function allows public process events to be broadcasted to an + /// additional listener on top of the default process event listener. + /// If the `listener` argument is invalid (SBListener::IsValid() will + /// return false), this will clear the shadow listener. + void SetShadowListener(SBListener &listener); + uint32_t GetNumArguments(); const char *GetArgumentAtIndex(uint32_t idx); diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -380,6 +380,10 @@ return GetStaticBroadcasterClass(); } + void SetShadowListener(lldb::ListenerSP listener_sp) override { + Broadcaster::SetShadowListener(listener_sp); + } + /// A notification structure that can be used by clients to listen /// for changes in a process's lifetime. /// diff --git a/lldb/include/lldb/Utility/Broadcaster.h b/lldb/include/lldb/Utility/Broadcaster.h --- a/lldb/include/lldb/Utility/Broadcaster.h +++ b/lldb/include/lldb/Utility/Broadcaster.h @@ -406,6 +406,10 @@ lldb::BroadcasterManagerSP GetManager(); + virtual void SetShadowListener(lldb::ListenerSP listener_sp) { + m_broadcaster_sp->m_shadow_listener = listener_sp; + } + protected: /// BroadcasterImpl contains the actual Broadcaster implementation. The /// Broadcaster makes a BroadcasterImpl which lives as long as it does. The @@ -513,6 +517,10 @@ /// for now this is just for private hijacking. std::vector m_hijacking_masks; + /// A optional listener that all private events get also broadcasted to, + /// on top the hijacked / default listeners. + lldb::ListenerSP m_shadow_listener = nullptr; + private: BroadcasterImpl(const BroadcasterImpl &) = delete; const BroadcasterImpl &operator=(const BroadcasterImpl &) = delete; diff --git a/lldb/include/lldb/Utility/Listener.h b/lldb/include/lldb/Utility/Listener.h --- a/lldb/include/lldb/Utility/Listener.h +++ b/lldb/include/lldb/Utility/Listener.h @@ -95,6 +95,8 @@ size_t HandleBroadcastEvent(lldb::EventSP &event_sp); + void SetShadow(bool is_shadow) { m_is_shadow = is_shadow; } + private: // Classes that inherit from Listener can see and modify these struct BroadcasterInfo { @@ -134,6 +136,7 @@ std::mutex m_events_mutex; // Protects m_broadcasters and m_events std::condition_variable m_events_condition; broadcaster_manager_collection m_broadcaster_managers; + bool m_is_shadow = false; void BroadcasterWillDestruct(Broadcaster *); diff --git a/lldb/include/lldb/Utility/ProcessInfo.h b/lldb/include/lldb/Utility/ProcessInfo.h --- a/lldb/include/lldb/Utility/ProcessInfo.h +++ b/lldb/include/lldb/Utility/ProcessInfo.h @@ -110,6 +110,12 @@ m_hijack_listener_sp = listener_sp; } + lldb::ListenerSP GetShadowListener() const { return m_shadow_listener_sp; } + + void SetShadowListener(const lldb::ListenerSP &listener_sp) { + m_shadow_listener_sp = listener_sp; + } + protected: FileSpec m_executable; std::string m_arg0; // argv[0] if supported. If empty, then use m_executable. @@ -124,6 +130,7 @@ lldb::ScriptedMetadataSP m_scripted_metadata_sp = nullptr; lldb::ListenerSP m_listener_sp = nullptr; lldb::ListenerSP m_hijack_listener_sp = nullptr; + lldb::ListenerSP m_shadow_listener_sp = nullptr; }; // ProcessInstanceInfo diff --git a/lldb/source/API/SBAttachInfo.cpp b/lldb/source/API/SBAttachInfo.cpp --- a/lldb/source/API/SBAttachInfo.cpp +++ b/lldb/source/API/SBAttachInfo.cpp @@ -254,6 +254,27 @@ m_opaque_sp->SetListener(listener.GetSP()); } +SBListener SBAttachInfo::GetShadowListener() { + LLDB_INSTRUMENT_VA(this); + + lldb::ListenerSP shadow_sp = m_opaque_sp->GetShadowListener(); + if (!shadow_sp) + return SBListener(); + return SBListener(shadow_sp); +} + +void SBAttachInfo::SetShadowListener(SBListener &listener) { + LLDB_INSTRUMENT_VA(this, listener); + + ListenerSP listener_sp = listener.GetSP(); + if (listener_sp && listener.IsValid()) + listener_sp->SetShadow(true); + else + listener_sp = nullptr; + + m_opaque_sp->SetShadowListener(listener_sp); +} + const char *SBAttachInfo::GetScriptedProcessClassName() const { LLDB_INSTRUMENT_VA(this); diff --git a/lldb/source/API/SBLaunchInfo.cpp b/lldb/source/API/SBLaunchInfo.cpp --- a/lldb/source/API/SBLaunchInfo.cpp +++ b/lldb/source/API/SBLaunchInfo.cpp @@ -17,6 +17,7 @@ #include "lldb/API/SBStructuredData.h" #include "lldb/Core/StructuredDataImpl.h" #include "lldb/Host/ProcessLaunchInfo.h" +#include "lldb/Utility/Listener.h" #include "lldb/Utility/ScriptedMetadata.h" using namespace lldb; @@ -387,3 +388,24 @@ metadata_sp = std::make_shared(class_name, dict_sp); m_opaque_sp->SetScriptedMetadata(metadata_sp); } + +SBListener SBLaunchInfo::GetShadowListener() { + LLDB_INSTRUMENT_VA(this); + + lldb::ListenerSP shadow_sp = m_opaque_sp->GetShadowListener(); + if (!shadow_sp) + return SBListener(); + return SBListener(shadow_sp); +} + +void SBLaunchInfo::SetShadowListener(SBListener &listener) { + LLDB_INSTRUMENT_VA(this, listener); + + ListenerSP listener_sp = listener.GetSP(); + if (listener_sp && listener.IsValid()) + listener_sp->SetShadow(true); + else + listener_sp = nullptr; + + m_opaque_sp->SetShadowListener(listener_sp); +} diff --git a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp --- a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -401,6 +401,7 @@ attach_info.SetHijackListener(listener_sp); } process_sp->HijackProcessEvents(listener_sp); + process_sp->SetShadowListener(attach_info.GetShadowListener()); error = process_sp->Attach(attach_info); } } @@ -458,6 +459,7 @@ LLDB_LOG(log, "successfully created process"); process_sp->HijackProcessEvents(launch_info.GetHijackListener()); + process_sp->SetShadowListener(launch_info.GetShadowListener()); // Log file actions. if (log) { diff --git a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp --- a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -423,6 +423,7 @@ if (process_sp) { process_sp->HijackProcessEvents(launch_info.GetHijackListener()); + process_sp->SetShadowListener(launch_info.GetShadowListener()); error = process_sp->ConnectRemote(connect_url.c_str()); // Retry the connect remote one time... @@ -515,6 +516,7 @@ ListenerSP listener_sp = attach_info.GetHijackListener(); if (listener_sp) process_sp->HijackProcessEvents(listener_sp); + process_sp->SetShadowListener(attach_info.GetShadowListener()); error = process_sp->Attach(attach_info); } diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -3194,6 +3194,7 @@ // Since we didn't have a platform launch the process, launch it here. if (m_process_sp) { m_process_sp->HijackProcessEvents(launch_info.GetHijackListener()); + m_process_sp->SetShadowListener(launch_info.GetShadowListener()); error = m_process_sp->Launch(launch_info); } } diff --git a/lldb/source/Utility/Broadcaster.cpp b/lldb/source/Utility/Broadcaster.cpp --- a/lldb/source/Utility/Broadcaster.cpp +++ b/lldb/source/Utility/Broadcaster.cpp @@ -228,6 +228,8 @@ &m_broadcaster, event_type)) return; hijacking_listener_sp->AddEvent(event_sp); + if (m_shadow_listener) + m_shadow_listener->AddEvent(event_sp); } else { for (auto &pair : GetListeners()) { if (!(pair.second & event_type)) @@ -237,6 +239,8 @@ continue; pair.first->AddEvent(event_sp); + if (m_shadow_listener) + m_shadow_listener->AddEvent(event_sp); } } } diff --git a/lldb/source/Utility/Listener.cpp b/lldb/source/Utility/Listener.cpp --- a/lldb/source/Utility/Listener.cpp +++ b/lldb/source/Utility/Listener.cpp @@ -35,7 +35,7 @@ Listener::Listener(const char *name) : m_name(name), m_broadcasters(), m_broadcasters_mutex(), m_events(), - m_events_mutex() { + m_events_mutex(), m_is_shadow() { Log *log = GetLog(LLDBLog::Object); if (log != nullptr) LLDB_LOGF(log, "%p Listener::Listener('%s')", static_cast(this), @@ -302,7 +302,8 @@ // to return it so it should be okay to get the next event off the queue // here - and it might be useful to do that in the "DoOnRemoval". lock.unlock(); - event_sp->DoOnRemoval(); + if (!m_is_shadow) + event_sp->DoOnRemoval(); } return true; } diff --git a/lldb/source/Utility/ProcessInfo.cpp b/lldb/source/Utility/ProcessInfo.cpp --- a/lldb/source/Utility/ProcessInfo.cpp +++ b/lldb/source/Utility/ProcessInfo.cpp @@ -23,13 +23,13 @@ ProcessInfo::ProcessInfo() : m_executable(), m_arguments(), m_environment(), m_arch(), m_listener_sp(), - m_hijack_listener_sp(), m_passthrough_listener_sp() {} + m_hijack_listener_sp(), m_shadow_listener_sp() {} ProcessInfo::ProcessInfo(const char *name, const ArchSpec &arch, lldb::pid_t pid) : m_executable(name), m_arguments(), m_environment(), m_arch(arch), m_pid(pid), m_listener_sp(), m_hijack_listener_sp(), - m_passthrough_listener_sp() {} + m_shadow_listener_sp() {} void ProcessInfo::Clear() { m_executable.Clear();