[Lldb-commits] [lldb] [LLDB][Part 1] Support enabling/disabling InstrumentationRuntime plugins in an debug session (PR #193328)
Dan Liew via lldb-commits
lldb-commits at lists.llvm.org
Thu Apr 30 11:58:39 PDT 2026
https://github.com/delcypher updated https://github.com/llvm/llvm-project/pull/193328
>From f24a8a9bcde8cdbf31215a2e69a808213588645f Mon Sep 17 00:00:00 2001
From: Dan Liew <dan at su-root.co.uk>
Date: Wed, 15 Apr 2026 11:49:08 -0700
Subject: [PATCH 1/4] [LLDB][Part 1] Support enabling/disabling
InstrumentationRuntime plugins in an debug session
This patch is the first part in a patch series that will allow
enabling/disabling InstrumentationRuntime plugins in a running debug
session.
This part adds the `--domain` flag to the `enable, `disable`, `list` sub
commands of `plugin` shell command and plumbs the value of this flag to
where it will be needed in subsequent patch. From the user perspective
the flag does nothing useful yet because all values passed to flag
except `global` (the default and what represents LLDB's existing
behavior) are rejected. Subsequent patches will allow the flag to do
something useful.
The `--domain` flag adds a notion of "domain" to plugins with respect to
their enablement. Previously all plugins were treated as global and have
their enablement stored globally. This is despite the fact that some
plugins clearly are not global. For example the
`instrumentation-runtime` plugins clearly exist on a per-target basis
(the instances of the `InstrumentationRuntime` exist in each process).
In addition to this plugins being "global" means instances of the
`Debugger` instance are not properly isolated from each other. This PR
is a stepping stone towards fixing these design problem. The PR
introduces three different domains for plugins:
* `global` - Enablement of the plugin can be controlled globally. This is the existing behavior of all LLDB plugins.
* `debugger` - Enablement of the plugin can be controlled on a per `Debugger` basis.
* `target` - Enablement of the plugin can be controlled on a per `Target` basis.
These values are encoded in the new `PluginDomainKind` enum.
It is important to note that the design in this PR means a plugin can
support more than one domain. In particular in future patches when
`instrumentation-runtime` plugins gain support for more than just the
`global` domain they will support the `debugger` and `target` domain as
well. The key reason that the `instrumentation-runtime` plugins need to
support more than one domain is that the plugins need a default
enablement value **before** the target exists. That default value will
need to come from the `global` domain. Architecturally it should
probably come from the `debugger` domain instead but refactoring
enablement into Debugger instances is much too large a refactor for this
patch series and is a problem that can be tackled later.
This patch modifies the `PluginNamespace` struct to:
* Store the set of domains supported by the namespace and provided some helper methods to determine what is supported.
* Store one of two callbacks. Either `SetPluginEnabledGlobalDomain` (the existing function interface used by most plugins) or
`SetPluginEnabledAllDomains` (a new interface used by `InstrumentationRuntime` plugins).
In this patch the `InstrumentationRuntime` plugins use the new
`SetPluginEnabledAllDomains` function interface for enablement (i.e. the
interface of `PluginManager::SetInstrumentationRuntimePluginEnabled` has
changed) which passes the `Debugger` instance that made the request and the
domain the user provided to the `plugin enable` or `plugin disable` command.
To make this patch easier to review the
`PluginManager::SetInstrumentationRuntimePluginEnabled` function actually
rejects all domains except `global` to keep the behavior change down to a
minimum. Proper support for enabling/disabling instrumentation-runtime plugins
in the `target`, and `debugger` domains will be implemented in a subsequent
patch.
The `plugin list` command implementations also reject any domain that isn't
`global`. Support for other domains will be added in the subsequent patch that
adds support for other domains in the `instrumentation-runtime` plugins.
The `plugin enable`, `plugin disable`, `plugin list` commands will use the
`global` domain by default so that there is no behavior change for existing
workflows.
Two new shell tests are included that exercise the new code paths:
* `command-plugin-enable-disable-domain-flag.test` validates that
`--domain global` works for both global-only and multi-domain plugin
namespaces, and that `--domain debugger` and `--domain target` are
correctly rejected for now.
* `command-plugin-list-domain-flag.test` validates the same behavior
for the list command in both text and JSON output modes.
I am not experienced at adding flags to LLDB shell commands so I had Claude
Code write that part and also help write test cases.
Assisted-by: Claude Code
rdar://167725878
---
lldb/include/lldb/Core/PluginManager.h | 61 ++++++-
.../Interpreter/CommandOptionArgumentTable.h | 9 +
lldb/include/lldb/lldb-enumerations.h | 7 +
lldb/source/Commands/CommandObjectPlugin.cpp | 171 ++++++++++++++++--
lldb/source/Commands/Options.td | 17 ++
lldb/source/Core/PluginManager.cpp | 25 ++-
...and-plugin-enable-disable-domain-flag.test | 59 ++++++
.../command-plugin-list-domain-flag.test | 56 ++++++
8 files changed, 379 insertions(+), 26 deletions(-)
create mode 100644 lldb/test/Shell/Commands/command-plugin-enable-disable-domain-flag.test
create mode 100644 lldb/test/Shell/Commands/command-plugin-list-domain-flag.test
diff --git a/lldb/include/lldb/Core/PluginManager.h b/lldb/include/lldb/Core/PluginManager.h
index 9403d3c34abec..848c946d58162 100644
--- a/lldb/include/lldb/Core/PluginManager.h
+++ b/lldb/include/lldb/Core/PluginManager.h
@@ -22,11 +22,13 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/JSON.h"
#include <cstddef>
#include <cstdint>
#include <functional>
+#include <variant>
#include <vector>
// Match the PluginInitCallback and PluginTermCallback signature. The generated
@@ -76,11 +78,57 @@ struct RegisteredPluginInfo {
// The plugin namespace here is used so we can operate on all the plugins
// of a given type so it is easy to enable or disable them as a group.
using GetPluginInfo = std::function<llvm::SmallVector<RegisteredPluginInfo>()>;
-using SetPluginEnabled = std::function<bool(llvm::StringRef, bool)>;
-struct PluginNamespace {
+using SetPluginEnabledGlobalDomain = std::function<bool(llvm::StringRef, bool)>;
+using SetPluginEnabledAllDomains = std::function<llvm::Error(
+ llvm::StringRef, bool, Debugger &, lldb::PluginDomainKind)>;
+class PluginNamespace {
+public:
+ static constexpr uint8_t kAllDomains = lldb::ePluginDomainKindGlobal |
+ lldb::ePluginDomainKindDebugger |
+ lldb::ePluginDomainKindTarget;
+
+ /// Plugin that is enabled/disabled globally.
+ PluginNamespace(llvm::StringRef name, GetPluginInfo get_info,
+ SetPluginEnabledGlobalDomain set_enabled)
+ : name(name), get_info(get_info),
+ supported_domains(lldb::ePluginDomainKindGlobal),
+ set_enabled_fn(set_enabled) {}
+
+ /// Plugin that is enabled/disabled on all domains.
+ PluginNamespace(llvm::StringRef name, GetPluginInfo get_info,
+ SetPluginEnabledAllDomains set_enabled)
+ : name(name), get_info(get_info), supported_domains(kAllDomains),
+ set_enabled_fn(set_enabled) {}
+
+ std::optional<SetPluginEnabledGlobalDomain> GetSetEnabledGlobalFn() const {
+ if (SupportsOnlyDomain(lldb::ePluginDomainKindGlobal))
+ return std::get<SetPluginEnabledGlobalDomain>(set_enabled_fn);
+ return std::nullopt;
+ }
+
+ std::optional<SetPluginEnabledAllDomains> GetSetEnabledAllDomainsFn() const {
+ if (supported_domains == kAllDomains)
+ return std::get<SetPluginEnabledAllDomains>(set_enabled_fn);
+ return std::nullopt;
+ }
+
+ bool SupportsDomain(lldb::PluginDomainKind domain) const {
+ assert(llvm::has_single_bit((uint8_t)domain));
+ return supported_domains & domain;
+ }
+
+ bool SupportsOnlyDomain(lldb::PluginDomainKind domain) const {
+ assert(llvm::has_single_bit((uint8_t)domain));
+ return supported_domains == domain;
+ }
+
llvm::StringRef name;
GetPluginInfo get_info;
- SetPluginEnabled set_enabled;
+
+private:
+ uint8_t supported_domains;
+ std::variant<SetPluginEnabledGlobalDomain, SetPluginEnabledAllDomains>
+ set_enabled_fn;
};
struct InstrumentationRuntimeCallbacks {
@@ -757,8 +805,11 @@ class PluginManager {
static llvm::SmallVector<RegisteredPluginInfo>
GetInstrumentationRuntimePluginInfo();
- static bool SetInstrumentationRuntimePluginEnabled(llvm::StringRef name,
- bool enable);
+ static llvm::StringRef PluginDomainKindToStr(lldb::PluginDomainKind kind);
+ static llvm::Error
+ SetInstrumentationRuntimePluginEnabled(llvm::StringRef name, bool enable,
+ Debugger &requesting_debugger,
+ lldb::PluginDomainKind domain);
static llvm::SmallVector<RegisteredPluginInfo> GetJITLoaderPluginInfo();
static bool SetJITLoaderPluginEnabled(llvm::StringRef name, bool enable);
diff --git a/lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h b/lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h
index 600b9639c4d4d..bdb23bf314aae 100644
--- a/lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h
+++ b/lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h
@@ -175,6 +175,14 @@ static constexpr OptionEnumValueElement g_name_match_style[] = {
"Match the identifier using a regular expression."},
};
+static constexpr OptionEnumValueElement g_plugin_domain_values[] = {
+ {lldb::ePluginDomainKindGlobal, "global",
+ "Apply to all debugger instances."},
+ {lldb::ePluginDomainKindDebugger, "debugger",
+ "Apply to the current debugger instance."},
+ {lldb::ePluginDomainKindTarget, "target", "Apply to the current target."},
+};
+
static constexpr OptionEnumValueElement g_completion_type[] = {
{lldb::eNoCompletion, "none", "No completion."},
{lldb::eSourceFileCompletion, "source-file", "Completes to a source file."},
@@ -340,6 +348,7 @@ static constexpr CommandObject::ArgumentTableEntry g_argument_table[] = {
{ lldb::eArgTypeProtocol, "protocol", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "The name of the protocol." },
{ lldb::eArgTypeExceptionStage, "exception-stage", lldb::CompletionType::eNoCompletion, g_exception_stage, { nullptr, false }, "Specify at which stage of the exception raise to stop." },
{ lldb::eArgTypeNameMatchStyle, "match-style", lldb::CompletionType::eNoCompletion, g_name_match_style, { nullptr, false }, "Specify the kind of match to use when looking up names." },
+ { lldb::eArgTypePluginDomain, "plugin-domain", lldb::CompletionType::eNoCompletion, g_plugin_domain_values, { nullptr, false }, "The domain to apply the plugin operation to." },
// clang-format on
};
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index e22d2e6a1374a..9b21af2e9882e 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -556,6 +556,12 @@ enum InstrumentationRuntimeType {
eNumInstrumentationRuntimeTypes
};
+enum PluginDomainKind {
+ ePluginDomainKindGlobal = 0x1,
+ ePluginDomainKindDebugger = 0x2,
+ ePluginDomainKindTarget = 0x4,
+};
+
enum DynamicValueType {
eNoDynamicValues = 0,
eDynamicCanRunTarget = 1,
@@ -684,6 +690,7 @@ enum CommandArgumentType {
eArgTypeProtocol,
eArgTypeExceptionStage,
eArgTypeNameMatchStyle,
+ eArgTypePluginDomain,
eArgTypeLastArg // Always keep this entry as the last entry in this
// enumeration!!
};
diff --git a/lldb/source/Commands/CommandObjectPlugin.cpp b/lldb/source/Commands/CommandObjectPlugin.cpp
index c0ea20d0e9b22..0d9c8ab89cd39 100644
--- a/lldb/source/Commands/CommandObjectPlugin.cpp
+++ b/lldb/source/Commands/CommandObjectPlugin.cpp
@@ -10,7 +10,9 @@
#include "lldb/Core/PluginManager.h"
#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandOptionArgumentTable.h"
#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/OptionArgParser.h"
using namespace lldb;
using namespace lldb_private;
@@ -83,22 +85,67 @@ static int ActOnMatchingPlugins(
// Used to share the majority of the code between the enable
// and disable commands.
int SetEnableOnMatchingPlugins(const llvm::StringRef &pattern,
- CommandReturnObject &result, bool enabled) {
+ CommandReturnObject &result, bool enabled,
+ Debugger &requesting_debugger,
+ PluginDomainKind domain) {
return ActOnMatchingPlugins(
pattern, [&](const PluginNamespace &plugin_namespace,
const std::vector<RegisteredPluginInfo> &plugins) {
+ auto PrintEnablement = [enabled,
+ &result](const RegisteredPluginInfo plugin) {
+ result.AppendMessageWithFormatv(" {0} {1, -30} {2}",
+ enabled ? "[+]" : "[-]", plugin.name,
+ plugin.description);
+ };
+
result.AppendMessage(plugin_namespace.name);
for (const auto &plugin : plugins) {
- if (!plugin_namespace.set_enabled(plugin.name, enabled)) {
- result.AppendErrorWithFormat("failed to enable plugin %s.%s",
- plugin_namespace.name.data(),
- plugin.name.data());
+ if (plugin_namespace.SupportsOnlyDomain(
+ PluginDomainKind::ePluginDomainKindGlobal)) {
+ bool success = true;
+ if (domain != ePluginDomainKindGlobal) {
+ result.AppendErrorWithFormatv(
+ "failed to {} plugin {}.{}: {} domain is not supported",
+ enabled ? "enable" : "disable", plugin_namespace.name,
+ plugin.name, PluginManager::PluginDomainKindToStr(domain));
+ continue;
+ }
+ success = (*plugin_namespace.GetSetEnabledGlobalFn())(plugin.name,
+ enabled);
+
+ if (!success) {
+ result.AppendErrorWithFormatv("failed to {} plugin {}.{}",
+ enabled ? "enable" : "disable",
+ plugin_namespace.name, plugin.name);
+ continue;
+ }
+ PrintEnablement(plugin);
continue;
}
- result.AppendMessageWithFormatv(" {0} {1, -30} {2}",
- enabled ? "[+]" : "[-]", plugin.name,
- plugin.description);
+ // Handle plugin namespace that supports more than just the global
+ // domain. Currently this is just the instrumentation-runtime
+ // namespace.
+ if (!plugin_namespace.SupportsDomain(domain)) {
+ result.AppendErrorWithFormatv(
+ "failed to {0} plugin {1}.{2}: because the {1} namespace "
+ "does not support the {3} domain",
+ enabled ? "enable" : "disable", plugin_namespace.name,
+ plugin.name, PluginManager::PluginDomainKindToStr(domain));
+ continue;
+ }
+ assert(plugin_namespace.GetSetEnabledAllDomainsFn().has_value());
+ llvm::Error error = (*plugin_namespace.GetSetEnabledAllDomainsFn())(
+ plugin.name, enabled, requesting_debugger, domain);
+
+ if (error) {
+ result.AppendErrorWithFormatv("failed to {} plugin {}.{}: {}",
+ enabled ? "enable" : "disable",
+ plugin_namespace.name, plugin.name,
+ llvm::toString(std::move(error)));
+ continue;
+ }
+ PrintEnablement(plugin);
}
});
}
@@ -116,6 +163,9 @@ static std::string ConvertJSONToPrettyString(const llvm::json::Value &json) {
// These option definitions are used by the plugin list command.
class PluginListCommandOptions : public Options {
+ static constexpr const PluginDomainKind kDefaultDomain =
+ ePluginDomainKindGlobal;
+
public:
PluginListCommandOptions() = default;
@@ -130,6 +180,11 @@ class PluginListCommandOptions : public Options {
case 'j':
m_json_format = true;
break;
+ case 'd':
+ m_domain = (PluginDomainKind)OptionArgParser::ToOptionEnum(
+ option_arg, GetDefinitions()[option_idx].enum_values, kDefaultDomain,
+ error);
+ break;
default:
llvm_unreachable("Unimplemented option");
}
@@ -139,6 +194,7 @@ class PluginListCommandOptions : public Options {
void OptionParsingStarting(ExecutionContext *execution_context) override {
m_json_format = false;
+ m_domain = kDefaultDomain;
}
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
@@ -147,6 +203,7 @@ class PluginListCommandOptions : public Options {
// Instance variables to hold the values for command options.
bool m_json_format = false;
+ PluginDomainKind m_domain = kDefaultDomain;
};
} // namespace
@@ -218,14 +275,23 @@ List only the plugin 'foo' matching a fully qualified name exactly
patterns.push_back(command[i].ref());
if (m_options.m_json_format)
- OutputJsonFormat(patterns, result);
+ OutputJsonFormat(patterns, result, GetDebugger(), m_options.m_domain);
else
- OutputTextFormat(patterns, result);
+ OutputTextFormat(patterns, result, GetDebugger(), m_options.m_domain);
}
private:
void OutputJsonFormat(const std::vector<llvm::StringRef> &patterns,
- CommandReturnObject &result) {
+ CommandReturnObject &result,
+ Debugger &requesting_debugger,
+ PluginDomainKind domain) {
+ if (domain != PluginDomainKind::ePluginDomainKindGlobal) {
+ result.AppendErrorWithFormatv(
+ "{} domain is not supported",
+ PluginManager::PluginDomainKindToStr(domain));
+ return;
+ }
+
llvm::json::Object obj;
bool found_empty = false;
for (const llvm::StringRef pattern : patterns) {
@@ -246,7 +312,16 @@ List only the plugin 'foo' matching a fully qualified name exactly
}
void OutputTextFormat(const std::vector<llvm::StringRef> &patterns,
- CommandReturnObject &result) {
+ CommandReturnObject &result,
+ Debugger &requesting_debugger,
+ PluginDomainKind domain) {
+ if (domain != PluginDomainKind::ePluginDomainKindGlobal) {
+ result.AppendErrorWithFormatv(
+ "{} domain is not supported",
+ PluginManager::PluginDomainKindToStr(domain));
+ return;
+ }
+
for (const llvm::StringRef pattern : patterns) {
int num_matching = ActOnMatchingPlugins(
pattern, [&](const PluginNamespace &plugin_namespace,
@@ -270,7 +345,8 @@ List only the plugin 'foo' matching a fully qualified name exactly
};
static void DoPluginEnableDisable(Args &command, CommandReturnObject &result,
- bool enable) {
+ bool enable, Debugger &requesting_debugger,
+ PluginDomainKind domain) {
const char *name = enable ? "enable" : "disable";
size_t argc = command.GetArgumentCount();
if (argc == 0) {
@@ -282,7 +358,8 @@ static void DoPluginEnableDisable(Args &command, CommandReturnObject &result,
for (size_t i = 0; i < argc; ++i) {
llvm::StringRef pattern = command[i].ref();
- int num_matching = SetEnableOnMatchingPlugins(pattern, result, enable);
+ int num_matching = SetEnableOnMatchingPlugins(pattern, result, enable,
+ requesting_debugger, domain);
if (num_matching == 0) {
result.AppendErrorWithFormat(
@@ -293,11 +370,58 @@ static void DoPluginEnableDisable(Args &command, CommandReturnObject &result,
}
}
+#define LLDB_OPTIONS_plugin_enable
+#include "CommandOptions.inc"
+
+#define LLDB_OPTIONS_plugin_disable
+#include "CommandOptions.inc"
+
+// Options class for the --domain flag, shared by plugin enable and
+// plugin disable (and reusable by plugin status in the future).
+class PluginDomainOptions : public Options {
+ static constexpr const PluginDomainKind kDefaultDomain =
+ ePluginDomainKindGlobal;
+
+public:
+ PluginDomainOptions(llvm::ArrayRef<OptionDefinition> definitions)
+ : m_definitions(definitions) {}
+
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
+ const int short_option = m_getopt_table[option_idx].val;
+ switch (short_option) {
+ case 'd':
+ m_domain = (PluginDomainKind)OptionArgParser::ToOptionEnum(
+ option_arg, GetDefinitions()[option_idx].enum_values, kDefaultDomain,
+ error);
+ break;
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+ return error;
+ }
+
+ void OptionParsingStarting(ExecutionContext *execution_context) override {
+ m_domain = kDefaultDomain;
+ }
+
+ llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
+ return m_definitions;
+ }
+
+ PluginDomainKind m_domain = kDefaultDomain;
+
+private:
+ llvm::ArrayRef<OptionDefinition> m_definitions;
+};
+
class CommandObjectPluginEnable : public CommandObjectParsed {
public:
CommandObjectPluginEnable(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "plugin enable",
- "Enable registered LLDB plugins.", nullptr) {
+ "Enable registered LLDB plugins.", nullptr),
+ m_options(llvm::ArrayRef(g_plugin_enable_options)) {
AddSimpleArgumentList(eArgTypeManagedPlugin);
}
@@ -311,17 +435,23 @@ class CommandObjectPluginEnable : public CommandObjectParsed {
~CommandObjectPluginEnable() override = default;
+ Options *GetOptions() override { return &m_options; }
+
protected:
void DoExecute(Args &command, CommandReturnObject &result) override {
- DoPluginEnableDisable(command, result, /*enable=*/true);
+ DoPluginEnableDisable(command, result, /*enable=*/true, GetDebugger(),
+ m_options.m_domain);
}
+
+ PluginDomainOptions m_options;
};
class CommandObjectPluginDisable : public CommandObjectParsed {
public:
CommandObjectPluginDisable(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "plugin disable",
- "Disable registered LLDB plugins.", nullptr) {
+ "Disable registered LLDB plugins.", nullptr),
+ m_options(llvm::ArrayRef(g_plugin_disable_options)) {
AddSimpleArgumentList(eArgTypeManagedPlugin);
}
@@ -335,10 +465,15 @@ class CommandObjectPluginDisable : public CommandObjectParsed {
~CommandObjectPluginDisable() override = default;
+ Options *GetOptions() override { return &m_options; }
+
protected:
void DoExecute(Args &command, CommandReturnObject &result) override {
- DoPluginEnableDisable(command, result, /*enable=*/false);
+ DoPluginEnableDisable(command, result, /*enable=*/false, GetDebugger(),
+ m_options.m_domain);
}
+
+ PluginDomainOptions m_options;
};
CommandObjectPlugin::CommandObjectPlugin(CommandInterpreter &interpreter)
diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td
index 98ac2134b44c7..12e06d4f8b2ad 100644
--- a/lldb/source/Commands/Options.td
+++ b/lldb/source/Commands/Options.td
@@ -1233,6 +1233,23 @@ let Command = "platform shell" in {
let Command = "plugin list" in {
def plugin_list_json : Option<"json", "j">,
Desc<"Output the plugin list in json format.">;
+ def plugin_list_domain : Option<"domain", "d">,
+ EnumArg<"PluginDomain">,
+ Desc<"The ${d}omain to list plugins for. Defaults to 'global'.">;
+}
+
+let Command = "plugin enable" in {
+ def plugin_enable_domain : Option<"domain", "d">,
+ EnumArg<"PluginDomain">,
+ Desc<"The ${d}omain in which to enable the "
+ "matching plugins. Defaults to 'global'.">;
+}
+
+let Command = "plugin disable" in {
+ def plugin_disable_domain : Option<"domain", "d">,
+ EnumArg<"PluginDomain">,
+ Desc<"The ${d}omain in which to disable the "
+ "matching plugins. Defaults to 'global'.">;
}
let Command = "process launch" in {
diff --git a/lldb/source/Core/PluginManager.cpp b/lldb/source/Core/PluginManager.cpp
index 39344ad7cd084..30e2a6aae22ba 100644
--- a/lldb/source/Core/PluginManager.cpp
+++ b/lldb/source/Core/PluginManager.cpp
@@ -2462,9 +2462,28 @@ llvm::SmallVector<RegisteredPluginInfo>
PluginManager::GetInstrumentationRuntimePluginInfo() {
return GetInstrumentationRuntimeInstances().GetPluginInfoForAllInstances();
}
-bool PluginManager::SetInstrumentationRuntimePluginEnabled(llvm::StringRef name,
- bool enable) {
- return GetInstrumentationRuntimeInstances().SetInstanceEnabled(name, enable);
+
+llvm::StringRef PluginManager::PluginDomainKindToStr(PluginDomainKind kind) {
+ switch (kind) {
+ case ePluginDomainKindGlobal:
+ return "global";
+ case ePluginDomainKindDebugger:
+ return "debugger";
+ case ePluginDomainKindTarget:
+ return "target";
+ }
+}
+
+llvm::Error PluginManager::SetInstrumentationRuntimePluginEnabled(
+ llvm::StringRef name, bool enable, Debugger &requesting_debugger,
+ PluginDomainKind domain) {
+ if (domain != lldb::ePluginDomainKindGlobal)
+ return llvm::createStringErrorV("{} domain is not supported",
+ PluginDomainKindToStr(domain));
+ if (!GetInstrumentationRuntimeInstances().SetInstanceEnabled(name, enable))
+ return llvm::createStringError("plugin could not be found");
+
+ return llvm::Error::success();
}
llvm::SmallVector<RegisteredPluginInfo>
diff --git a/lldb/test/Shell/Commands/command-plugin-enable-disable-domain-flag.test b/lldb/test/Shell/Commands/command-plugin-enable-disable-domain-flag.test
new file mode 100644
index 0000000000000..89468ce11293d
--- /dev/null
+++ b/lldb/test/Shell/Commands/command-plugin-enable-disable-domain-flag.test
@@ -0,0 +1,59 @@
+# This test validates the --domain flag on the plugin enable and disable
+# commands.
+#
+# Note that commands that return errors will stop running a script, so we
+# have new RUN lines for any command that is expected to return an error.
+
+# RUN: %lldb -s %s -o exit 2>&1 | FileCheck %s
+
+# Test --domain global on a non-instrumentation runtime plugin (GLOBAL domain).
+plugin disable --domain global language.cplusplus
+# CHECK-LABEL: plugin disable --domain global language.cplusplus
+# CHECK: language
+# CHECK: [-] cplusplus
+
+plugin enable --domain global language.cplusplus
+# CHECK-LABEL: plugin enable --domain global language.cplusplus
+# CHECK: language
+# CHECK: [+] cplusplus
+
+# Test --domain global on an instrumentation runtime plugin
+# (USER_SPECIFIED domain).
+plugin disable --domain global instrumentation-runtime.UndefinedBehaviorSanitizer
+# CHECK-LABEL: plugin disable --domain global instrumentation-runtime.UndefinedBehaviorSanitizer
+# CHECK: instrumentation-runtime
+# CHECK: [-] UndefinedBehaviorSanitizer
+
+plugin enable --domain global instrumentation-runtime.UndefinedBehaviorSanitizer
+# CHECK-LABEL: plugin enable --domain global instrumentation-runtime.UndefinedBehaviorSanitizer
+# CHECK: instrumentation-runtime
+# CHECK: [+] UndefinedBehaviorSanitizer
+
+# Error cases for GLOBAL-domain plugin (language.cplusplus).
+
+# RUN: %lldb -o "plugin enable --domain debugger language.cplusplus" 2>&1 | FileCheck %s --check-prefix=ERROR_ENABLE_GLOBAL_DEBUGGER
+# ERROR_ENABLE_GLOBAL_DEBUGGER: error: failed to enable plugin language.cplusplus: debugger domain is not supported
+
+# RUN: %lldb -o "plugin enable --domain target language.cplusplus" 2>&1 | FileCheck %s --check-prefix=ERROR_ENABLE_GLOBAL_TARGET
+# ERROR_ENABLE_GLOBAL_TARGET: error: failed to enable plugin language.cplusplus: target domain is not supported
+
+# RUN: %lldb -o "plugin disable --domain debugger language.cplusplus" 2>&1 | FileCheck %s --check-prefix=ERROR_DISABLE_GLOBAL_DEBUGGER
+# ERROR_DISABLE_GLOBAL_DEBUGGER: error: failed to disable plugin language.cplusplus: debugger domain is not supported
+
+# RUN: %lldb -o "plugin disable --domain target language.cplusplus" 2>&1 | FileCheck %s --check-prefix=ERROR_DISABLE_GLOBAL_TARGET
+# ERROR_DISABLE_GLOBAL_TARGET: error: failed to disable plugin language.cplusplus: target domain is not supported
+
+# Error cases for USER_SPECIFIED-domain plugin
+# (instrumentation-runtime.UndefinedBehaviorSanitizer).
+
+# RUN: %lldb -o "plugin enable --domain debugger instrumentation-runtime.UndefinedBehaviorSanitizer" 2>&1 | FileCheck %s --check-prefix=ERROR_ENABLE_IR_DEBUGGER
+# ERROR_ENABLE_IR_DEBUGGER: error: failed to enable plugin instrumentation-runtime.UndefinedBehaviorSanitizer: debugger domain is not supported
+
+# RUN: %lldb -o "plugin enable --domain target instrumentation-runtime.UndefinedBehaviorSanitizer" 2>&1 | FileCheck %s --check-prefix=ERROR_ENABLE_IR_TARGET
+# ERROR_ENABLE_IR_TARGET: error: failed to enable plugin instrumentation-runtime.UndefinedBehaviorSanitizer: target domain is not supported
+
+# RUN: %lldb -o "plugin disable --domain debugger instrumentation-runtime.UndefinedBehaviorSanitizer" 2>&1 | FileCheck %s --check-prefix=ERROR_DISABLE_IR_DEBUGGER
+# ERROR_DISABLE_IR_DEBUGGER: error: failed to disable plugin instrumentation-runtime.UndefinedBehaviorSanitizer: debugger domain is not supported
+
+# RUN: %lldb -o "plugin disable --domain target instrumentation-runtime.UndefinedBehaviorSanitizer" 2>&1 | FileCheck %s --check-prefix=ERROR_DISABLE_IR_TARGET
+# ERROR_DISABLE_IR_TARGET: error: failed to disable plugin instrumentation-runtime.UndefinedBehaviorSanitizer: target domain is not supported
diff --git a/lldb/test/Shell/Commands/command-plugin-list-domain-flag.test b/lldb/test/Shell/Commands/command-plugin-list-domain-flag.test
new file mode 100644
index 0000000000000..6565c95fd6439
--- /dev/null
+++ b/lldb/test/Shell/Commands/command-plugin-list-domain-flag.test
@@ -0,0 +1,56 @@
+# This test validates the --domain flag on the plugin list command.
+#
+# Note that commands that return errors will stop running a script, so we
+# have new RUN lines for any command that is expected to return an error.
+
+# RUN: %lldb -s %s -o exit 2>&1 | FileCheck %s
+
+# Test plugin list --domain global works with a non-instrumentation runtime
+# plugin (GLOBAL domain).
+plugin list --domain global language.cplusplus
+# CHECK-LABEL: plugin list --domain global language.cplusplus
+# CHECK: language
+# CHECK: [+] cplusplus
+
+# Test plugin list --domain global works with an instrumentation runtime
+# plugin (USER_SPECIFIED domain).
+plugin list --domain global instrumentation-runtime.UndefinedBehaviorSanitizer
+# CHECK-LABEL: plugin list --domain global instrumentation-runtime.UndefinedBehaviorSanitizer
+# CHECK: instrumentation-runtime
+# CHECK: [+] UndefinedBehaviorSanitizer
+
+# Error cases with on a plugin that's not an instrumentation-runtime
+
+# Test plugin list --domain debugger returns an error (text format).
+# RUN: %lldb -o "plugin list --domain debugger language.cplusplus" 2>&1 | FileCheck %s --check-prefix=ERROR_LIST_DEBUGGER
+# ERROR_LIST_DEBUGGER: error: debugger domain is not supported
+
+# Test plugin list --domain target returns an error (text format).
+# RUN: %lldb -o "plugin list --domain target language.cplusplus" 2>&1 | FileCheck %s --check-prefix=ERROR_LIST_TARGET
+# ERROR_LIST_TARGET: error: target domain is not supported
+
+# Test plugin list --domain debugger --json returns an error (json format).
+# RUN: %lldb -o "plugin list --domain debugger --json language.cplusplus" 2>&1 | FileCheck %s --check-prefix=ERROR_LIST_JSON_DEBUGGER
+# ERROR_LIST_JSON_DEBUGGER: error: debugger domain is not supported
+
+# Test plugin list --domain target --json returns an error (json format).
+# RUN: %lldb -o "plugin list --domain target --json language.cplusplus" 2>&1 | FileCheck %s --check-prefix=ERROR_LIST_JSON_TARGET
+# ERROR_LIST_JSON_TARGET: error: target domain is not supported
+
+# Error cases with on a plugin that's an instrumentation-runtime
+
+# Test plugin list --domain debugger returns an error for instrumentation-runtime plugin (text format).
+# RUN: %lldb -o "plugin list --domain debugger instrumentation-runtime.UndefinedBehaviorSanitizer" 2>&1 | FileCheck %s --check-prefix=ERROR_LIST_DEBUGGER_IR
+# ERROR_LIST_DEBUGGER_IR: error: debugger domain is not supported
+
+# Test plugin list --domain target returns an error for instrumentation-runtime plugin (text format).
+# RUN: %lldb -o "plugin list --domain target instrumentation-runtime.UndefinedBehaviorSanitizer" 2>&1 | FileCheck %s --check-prefix=ERROR_LIST_TARGET_IR
+# ERROR_LIST_TARGET_IR: error: target domain is not supported
+
+# Test plugin list --domain debugger --json returns an error for instrumentation-runtime plugin (json format).
+# RUN: %lldb -o "plugin list --domain debugger --json instrumentation-runtime.UndefinedBehaviorSanitizer" 2>&1 | FileCheck %s --check-prefix=ERROR_LIST_JSON_DEBUGGER_IR
+# ERROR_LIST_JSON_DEBUGGER_IR: error: debugger domain is not supported
+
+# Test plugin list --domain target --json returns an error for instrumentation-runtime plugin (json format).
+# RUN: %lldb -o "plugin list --domain target --json instrumentation-runtime.UndefinedBehaviorSanitizer" 2>&1 | FileCheck %s --check-prefix=ERROR_LIST_JSON_TARGET_IR
+# ERROR_LIST_JSON_TARGET_IR: error: target domain is not supported
>From 8ee04f9bb87666269cc0b62f295e93790745b497 Mon Sep 17 00:00:00 2001
From: Dan Liew <dan at su-root.co.uk>
Date: Tue, 21 Apr 2026 15:31:30 -0700
Subject: [PATCH 2/4] Fix `PluginManagerTest, MatchPluginName` unit test
---
lldb/unittests/Core/PluginManagerTest.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lldb/unittests/Core/PluginManagerTest.cpp b/lldb/unittests/Core/PluginManagerTest.cpp
index 695f6987ba46a..61b4cb8993293 100644
--- a/lldb/unittests/Core/PluginManagerTest.cpp
+++ b/lldb/unittests/Core/PluginManagerTest.cpp
@@ -381,7 +381,8 @@ TEST_F(PluginManagerTest, UnRegisterSystemRuntimePluginChangesOrder) {
}
TEST_F(PluginManagerTest, MatchPluginName) {
- PluginNamespace Foo{"foo", nullptr, nullptr};
+ auto TmpFn = [](llvm::StringRef, bool) -> bool { return true; };
+ PluginNamespace Foo{"foo", nullptr, TmpFn};
RegisteredPluginInfo Bar{"bar", "bar plugin ", true};
RegisteredPluginInfo Baz{"baz", "baz plugin ", true};
>From 0d8f6d78b02a2c4dfc5382f724edcf0b4865d80e Mon Sep 17 00:00:00 2001
From: Dan Liew <dan at su-root.co.uk>
Date: Tue, 21 Apr 2026 17:15:58 -0700
Subject: [PATCH 3/4] Comment tweak
---
lldb/include/lldb/Core/PluginManager.h | 4 ++--
.../command-plugin-enable-disable-domain-flag.test | 7 +++----
.../Shell/Commands/command-plugin-list-domain-flag.test | 8 ++++----
3 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/lldb/include/lldb/Core/PluginManager.h b/lldb/include/lldb/Core/PluginManager.h
index 848c946d58162..c2ef6b3fc2448 100644
--- a/lldb/include/lldb/Core/PluginManager.h
+++ b/lldb/include/lldb/Core/PluginManager.h
@@ -87,14 +87,14 @@ class PluginNamespace {
lldb::ePluginDomainKindDebugger |
lldb::ePluginDomainKindTarget;
- /// Plugin that is enabled/disabled globally.
+ /// Plugin that only supports enable/disable in the global domain
PluginNamespace(llvm::StringRef name, GetPluginInfo get_info,
SetPluginEnabledGlobalDomain set_enabled)
: name(name), get_info(get_info),
supported_domains(lldb::ePluginDomainKindGlobal),
set_enabled_fn(set_enabled) {}
- /// Plugin that is enabled/disabled on all domains.
+ /// Plugin that supports enable/disable in all domains.
PluginNamespace(llvm::StringRef name, GetPluginInfo get_info,
SetPluginEnabledAllDomains set_enabled)
: name(name), get_info(get_info), supported_domains(kAllDomains),
diff --git a/lldb/test/Shell/Commands/command-plugin-enable-disable-domain-flag.test b/lldb/test/Shell/Commands/command-plugin-enable-disable-domain-flag.test
index 89468ce11293d..6cdc900c261c1 100644
--- a/lldb/test/Shell/Commands/command-plugin-enable-disable-domain-flag.test
+++ b/lldb/test/Shell/Commands/command-plugin-enable-disable-domain-flag.test
@@ -6,7 +6,7 @@
# RUN: %lldb -s %s -o exit 2>&1 | FileCheck %s
-# Test --domain global on a non-instrumentation runtime plugin (GLOBAL domain).
+# Test --domain global on a non-instrumentation runtime plugin.
plugin disable --domain global language.cplusplus
# CHECK-LABEL: plugin disable --domain global language.cplusplus
# CHECK: language
@@ -18,7 +18,6 @@ plugin enable --domain global language.cplusplus
# CHECK: [+] cplusplus
# Test --domain global on an instrumentation runtime plugin
-# (USER_SPECIFIED domain).
plugin disable --domain global instrumentation-runtime.UndefinedBehaviorSanitizer
# CHECK-LABEL: plugin disable --domain global instrumentation-runtime.UndefinedBehaviorSanitizer
# CHECK: instrumentation-runtime
@@ -29,7 +28,7 @@ plugin enable --domain global instrumentation-runtime.UndefinedBehaviorSanitizer
# CHECK: instrumentation-runtime
# CHECK: [+] UndefinedBehaviorSanitizer
-# Error cases for GLOBAL-domain plugin (language.cplusplus).
+# Error cases for plugin that only supports the global domain (language.cplusplus).
# RUN: %lldb -o "plugin enable --domain debugger language.cplusplus" 2>&1 | FileCheck %s --check-prefix=ERROR_ENABLE_GLOBAL_DEBUGGER
# ERROR_ENABLE_GLOBAL_DEBUGGER: error: failed to enable plugin language.cplusplus: debugger domain is not supported
@@ -43,7 +42,7 @@ plugin enable --domain global instrumentation-runtime.UndefinedBehaviorSanitizer
# RUN: %lldb -o "plugin disable --domain target language.cplusplus" 2>&1 | FileCheck %s --check-prefix=ERROR_DISABLE_GLOBAL_TARGET
# ERROR_DISABLE_GLOBAL_TARGET: error: failed to disable plugin language.cplusplus: target domain is not supported
-# Error cases for USER_SPECIFIED-domain plugin
+# Error cases for plugin that supports all domains
# (instrumentation-runtime.UndefinedBehaviorSanitizer).
# RUN: %lldb -o "plugin enable --domain debugger instrumentation-runtime.UndefinedBehaviorSanitizer" 2>&1 | FileCheck %s --check-prefix=ERROR_ENABLE_IR_DEBUGGER
diff --git a/lldb/test/Shell/Commands/command-plugin-list-domain-flag.test b/lldb/test/Shell/Commands/command-plugin-list-domain-flag.test
index 6565c95fd6439..7aacb522843c7 100644
--- a/lldb/test/Shell/Commands/command-plugin-list-domain-flag.test
+++ b/lldb/test/Shell/Commands/command-plugin-list-domain-flag.test
@@ -6,20 +6,20 @@
# RUN: %lldb -s %s -o exit 2>&1 | FileCheck %s
# Test plugin list --domain global works with a non-instrumentation runtime
-# plugin (GLOBAL domain).
+# plugin.
plugin list --domain global language.cplusplus
# CHECK-LABEL: plugin list --domain global language.cplusplus
# CHECK: language
# CHECK: [+] cplusplus
# Test plugin list --domain global works with an instrumentation runtime
-# plugin (USER_SPECIFIED domain).
+# plugin.
plugin list --domain global instrumentation-runtime.UndefinedBehaviorSanitizer
# CHECK-LABEL: plugin list --domain global instrumentation-runtime.UndefinedBehaviorSanitizer
# CHECK: instrumentation-runtime
# CHECK: [+] UndefinedBehaviorSanitizer
-# Error cases with on a plugin that's not an instrumentation-runtime
+# Error cases with on a plugin that only supports the global domain.
# Test plugin list --domain debugger returns an error (text format).
# RUN: %lldb -o "plugin list --domain debugger language.cplusplus" 2>&1 | FileCheck %s --check-prefix=ERROR_LIST_DEBUGGER
@@ -37,7 +37,7 @@ plugin list --domain global instrumentation-runtime.UndefinedBehaviorSanitizer
# RUN: %lldb -o "plugin list --domain target --json language.cplusplus" 2>&1 | FileCheck %s --check-prefix=ERROR_LIST_JSON_TARGET
# ERROR_LIST_JSON_TARGET: error: target domain is not supported
-# Error cases with on a plugin that's an instrumentation-runtime
+# Error cases with on a plugin that supports all domains.
# Test plugin list --domain debugger returns an error for instrumentation-runtime plugin (text format).
# RUN: %lldb -o "plugin list --domain debugger instrumentation-runtime.UndefinedBehaviorSanitizer" 2>&1 | FileCheck %s --check-prefix=ERROR_LIST_DEBUGGER_IR
>From a912c48eaf9c7e15da6713557a2fd12ef438ecf5 Mon Sep 17 00:00:00 2001
From: Dan Liew <dan at su-root.co.uk>
Date: Thu, 30 Apr 2026 11:57:44 -0700
Subject: [PATCH 4/4] Address review feedback
---
lldb/include/lldb/Core/PluginManager.h | 4 ++--
lldb/source/Commands/CommandObjectPlugin.cpp | 10 +++++-----
lldb/source/Core/PluginManager.cpp | 1 +
3 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/lldb/include/lldb/Core/PluginManager.h b/lldb/include/lldb/Core/PluginManager.h
index c2ef6b3fc2448..e93c46f13e353 100644
--- a/lldb/include/lldb/Core/PluginManager.h
+++ b/lldb/include/lldb/Core/PluginManager.h
@@ -113,12 +113,12 @@ class PluginNamespace {
}
bool SupportsDomain(lldb::PluginDomainKind domain) const {
- assert(llvm::has_single_bit((uint8_t)domain));
+ assert(llvm::has_single_bit(static_cast<uint8_t>(domain)));
return supported_domains & domain;
}
bool SupportsOnlyDomain(lldb::PluginDomainKind domain) const {
- assert(llvm::has_single_bit((uint8_t)domain));
+ assert(llvm::has_single_bit(static_cast<uint8_t>(domain)));
return supported_domains == domain;
}
diff --git a/lldb/source/Commands/CommandObjectPlugin.cpp b/lldb/source/Commands/CommandObjectPlugin.cpp
index 0d9c8ab89cd39..396910abfb8b8 100644
--- a/lldb/source/Commands/CommandObjectPlugin.cpp
+++ b/lldb/source/Commands/CommandObjectPlugin.cpp
@@ -128,7 +128,7 @@ int SetEnableOnMatchingPlugins(const llvm::StringRef &pattern,
// namespace.
if (!plugin_namespace.SupportsDomain(domain)) {
result.AppendErrorWithFormatv(
- "failed to {0} plugin {1}.{2}: because the {1} namespace "
+ "failed to {0} plugin {1}.{2}: the {1} namespace "
"does not support the {3} domain",
enabled ? "enable" : "disable", plugin_namespace.name,
plugin.name, PluginManager::PluginDomainKindToStr(domain));
@@ -181,9 +181,9 @@ class PluginListCommandOptions : public Options {
m_json_format = true;
break;
case 'd':
- m_domain = (PluginDomainKind)OptionArgParser::ToOptionEnum(
+ m_domain = static_cast<PluginDomainKind>(OptionArgParser::ToOptionEnum(
option_arg, GetDefinitions()[option_idx].enum_values, kDefaultDomain,
- error);
+ error));
break;
default:
llvm_unreachable("Unimplemented option");
@@ -392,9 +392,9 @@ class PluginDomainOptions : public Options {
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
case 'd':
- m_domain = (PluginDomainKind)OptionArgParser::ToOptionEnum(
+ m_domain = static_cast<PluginDomainKind>(OptionArgParser::ToOptionEnum(
option_arg, GetDefinitions()[option_idx].enum_values, kDefaultDomain,
- error);
+ error));
break;
default:
llvm_unreachable("Unimplemented option");
diff --git a/lldb/source/Core/PluginManager.cpp b/lldb/source/Core/PluginManager.cpp
index 30e2a6aae22ba..020ab2dc68dfc 100644
--- a/lldb/source/Core/PluginManager.cpp
+++ b/lldb/source/Core/PluginManager.cpp
@@ -2472,6 +2472,7 @@ llvm::StringRef PluginManager::PluginDomainKindToStr(PluginDomainKind kind) {
case ePluginDomainKindTarget:
return "target";
}
+ llvm_unreachable("unhandled PluginDomainKind");
}
llvm::Error PluginManager::SetInstrumentationRuntimePluginEnabled(
More information about the lldb-commits
mailing list