[Lldb-commits] [lldb] [LLDB] Add module hook implementation (PR #185465)

via lldb-commits lldb-commits at lists.llvm.org
Wed Mar 18 10:53:07 PDT 2026


================
@@ -1640,6 +1641,171 @@ class Target : public std::enable_shared_from_this<Target>,
 
   typedef std::shared_ptr<StopHook> StopHookSP;
 
+  // Target Hooks
+  //
+  // Hooks fire on lifecycle events. By default, they fire when modules
+  // are loaded into the target (via ModulesDidLoad). They can also fire
+  // on module unload (via ModulesDidUnload) and on process stop (via
+  // RunStopHooks), controlled by the event mask.
+  class Hook : public UserID {
+  public:
+    Hook(const Hook &rhs);
+    virtual ~Hook() = default;
+
+    enum class HookKind : uint32_t { CommandBased = 0, ScriptBased };
+
+    /// Event mask bits controlling when this hook fires.
+    // FIXME: Add more event types as needed, e.g.:
+    //  kProcessExited (fires when the process exits).
+    //  kProcessDetached (fires when the debugger detaches).
+    enum EventMask : uint32_t {
+      kModulesLoaded = (1u << 0),
+      kModulesUnloaded = (1u << 1),
+      kProcessStop = (1u << 2),
+    };
+
+    lldb::TargetSP &GetTarget() { return m_target_sp; }
+
+    bool IsActive() { return m_active; }
+    void SetIsActive(bool is_active) { m_active = is_active; }
+
+    uint32_t GetEventMask() const { return m_event_mask; }
+    void SetEventMask(uint32_t mask) { m_event_mask = mask; }
+    void AddEvent(uint32_t event) { m_event_mask |= event; }
+    void RemoveEvent(uint32_t event) { m_event_mask &= ~event; }
+    bool FiresOn(uint32_t event) const { return m_event_mask & event; }
+
+    // Filter fields
+
+    /// Set the symbol context specifier. The hook takes ownership.
+    void SetSCSpecifier(SymbolContextSpecifier *specifier);
+    SymbolContextSpecifier *GetSCSpecifier() { return m_sc_specifier_sp.get(); }
+
+    /// Check if the execution context passes the specifier and thread spec
+    /// filters. Always returns true if no filters are set.
+    bool ExecutionContextPasses(const ExecutionContext &exe_ctx);
+
+    /// Set the thread specifier. The hook takes ownership.
+    void SetThreadSpecifier(ThreadSpec *specifier);
+    ThreadSpec *GetThreadSpecifier() { return m_thread_spec_up.get(); }
+
+    void SetAutoContinue(bool auto_continue) {
+      m_auto_continue = auto_continue;
+    }
+    bool GetAutoContinue() const { return m_auto_continue; }
+
+    void SetRunAtInitialStop(bool at_initial_stop) {
+      m_at_initial_stop = at_initial_stop;
+    }
+    bool GetRunAtInitialStop() const { return m_at_initial_stop; }
+
+    void SetSuppressOutput(bool suppress_output) {
+      m_suppress_output = suppress_output;
+    }
+    bool GetSuppressOutput() const { return m_suppress_output; }
+
+    // Event handler methods
+
+    virtual void HandleModuleLoaded(lldb::StreamSP output) = 0;
+    virtual void HandleModuleUnloaded(lldb::StreamSP output) = 0;
+
+    /// Called when the process stops. Returns a StopHookResult indicating
+    /// whether the process should remain stopped or continue.
+    virtual StopHook::StopHookResult HandleStop(ExecutionContext &exe_ctx,
+                                                lldb::StreamSP output) = 0;
+
+    virtual void GetDescription(Stream &s, lldb::DescriptionLevel level) const;
+
+  protected:
+    lldb::TargetSP m_target_sp;
+    bool m_active = true;
+    uint32_t m_event_mask = kModulesLoaded; // Default: fire on load only
----------------
jimingham wrote:

This is a generic hook interface that over time will accrue more "lifecycle events" that are supported by this hook class.  So it's odd that is starts seemingly requiring response to one type of trigger?  It would be weird to make a hook with no triggers, but it should be possible.  And privileging one seems more wrong than allowing an empty one.

https://github.com/llvm/llvm-project/pull/185465


More information about the lldb-commits mailing list