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

via lldb-commits lldb-commits at lists.llvm.org
Wed Mar 18 11:02:13 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
+
+    lldb::SymbolContextSpecifierSP m_sc_specifier_sp;
+    std::unique_ptr<ThreadSpec> m_thread_spec_up;
+    bool m_auto_continue = false;
+    bool m_at_initial_stop = true;
+    bool m_suppress_output = false;
+
+    Hook(lldb::TargetSP target_sp, lldb::user_id_t uid);
+  };
+
+  class HookCommandLine : public Hook {
+  public:
+    ~HookCommandLine() override = default;
+
+    /// Return the list of commands that this hook runs.
+    StringList &GetCommands() { return m_commands; }
----------------
jimingham wrote:

I don't actually understand how these API's work in the case of a CommandLine Hook that implements more than one "EventMask bit" - what I was suggesting we call "Triggers".

Wouldn't you want 

SetActionFromString(EventMask trigger_bit, const std::string &actions);

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


More information about the lldb-commits mailing list