[Lldb-commits] [lldb] [lldb] Add `scripting extension instances` command (PR #226043)
via lldb-commits
lldb-commits at lists.llvm.org
Thu Sep 24 00:15:23 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
Author: Med Ismail Bennani (medismailben)
<details>
<summary>Changes</summary>
There is currently no way to tell which scripted extensions are alive in a debug session, or which script file a given extension class came from.
This patch addresses that by recording the file of every module imported by the script interpreter, and attributing it to the ScriptedMetadata of each extension object created from one of its classes. It tracks every successfully created extension object in a registry owned by the script interpreter, and lists them with the new `scripting extension instances` command, grouped by class. Each instance shows a UUID, the address of its script object and the arguments it was created with:
```
(lldb) scripting extension instances
Instantiated scripted extensions:
--------------------------------------------------------------------------------
Class: resolver.Resolver
Extension: ScriptedBreakpointResolver
Path: /tmp/resolver.py
Instance: 430F093E-89C6-EEF1-9602-E951A3A523DF (0x90000759e54f1a0)
Args:
- symbol: break_on_me
--------------------------------------------------------------------------------
Class: stop_hook.stop_handler
Extension: ScriptedHook
Path: /tmp/stop_hook.py
Instances:
[0] 7576EB2F-4E4D-1931-D006-F632A51696BD (0x50000784d2584a0)
Args:
- increment: 5
[1] C95B90A2-E199-343F-B7F7-AC2E360BFF2F (0x50000759e54dfa0)
Args:
- increment: 1
- return_false: 1
```
---
Patch is 35.58 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/226043.diff
15 Files Affected:
- (modified) lldb/include/lldb/Interpreter/Interfaces/ScriptedInterface.h (+39-1)
- (modified) lldb/include/lldb/Interpreter/ScriptInterpreter.h (+19)
- (added) lldb/include/lldb/Interpreter/ScriptedInstanceRegistry.h (+97)
- (modified) lldb/include/lldb/Utility/ScriptedMetadata.h (+8)
- (modified) lldb/include/lldb/lldb-forward.h (+5)
- (modified) lldb/source/Commands/CommandObjectScripting.cpp (+115)
- (modified) lldb/source/Commands/Options.td (+6)
- (modified) lldb/source/Interpreter/CMakeLists.txt (+1)
- (modified) lldb/source/Interpreter/ScriptInterpreter.cpp (+20)
- (added) lldb/source/Interpreter/ScriptedInstanceRegistry.cpp (+153)
- (modified) lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h (+17)
- (modified) lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp (+15)
- (added) lldb/test/API/commands/scripting/extension/TestScriptingExtensionInstances.py (+154)
- (added) lldb/test/API/commands/scripting/extension/instance_cmds.py (+17)
- (modified) lldb/unittests/Interpreter/TestScriptedInterface.cpp (+45)
``````````diff
diff --git a/lldb/include/lldb/Interpreter/Interfaces/ScriptedInterface.h b/lldb/include/lldb/Interpreter/Interfaces/ScriptedInterface.h
index 79c2f08a1820b..d01699fe27022 100644
--- a/lldb/include/lldb/Interpreter/Interfaces/ScriptedInterface.h
+++ b/lldb/include/lldb/Interpreter/Interfaces/ScriptedInterface.h
@@ -10,6 +10,7 @@
#define LLDB_INTERPRETER_INTERFACES_SCRIPTEDINTERFACE_H
#include "ScriptedInterfaceUsages.h"
+#include "lldb/Interpreter/ScriptedInstanceRegistry.h"
#include "lldb/Core/StructuredDataImpl.h"
#include "lldb/Utility/LLDBLog.h"
@@ -27,7 +28,12 @@ namespace lldb_private {
class ScriptedInterface {
public:
ScriptedInterface() = default;
- virtual ~ScriptedInterface() = default;
+ virtual ~ScriptedInterface() { UnregisterInstance(); }
+
+ // Copies would share the registry entry, and the first one destroyed would
+ // drop it while the other is still alive.
+ ScriptedInterface(const ScriptedInterface &) = delete;
+ ScriptedInterface &operator=(const ScriptedInterface &) = delete;
StructuredData::GenericSP GetScriptObjectInstance() {
return m_object_instance_sp;
@@ -37,6 +43,8 @@ class ScriptedInterface {
return m_scripted_metadata;
}
+ virtual llvm::StringRef GetPluginName() { return {}; }
+
/// Whether the user can invoke this extension directly, the way a scripted
/// command can. Those never introduce the target's API mutex bypass, so at
/// top level they serialize like any other command; nested inside an
@@ -101,8 +109,38 @@ class ScriptedInterface {
}
protected:
+ void RegisterInstance(const lldb::ScriptedInstanceRegistrySP ®istry_sp,
+ llvm::StringRef class_name) {
+ UnregisterInstance();
+ if (!registry_sp)
+ return;
+ ScriptedInstanceInfo info;
+ info.plugin_name = GetPluginName();
+ info.class_name = class_name.str();
+ if (m_object_instance_sp)
+ info.object_address =
+ reinterpret_cast<uintptr_t>(m_object_instance_sp->GetValue());
+ if (m_scripted_metadata) {
+ info.source_path = m_scripted_metadata->GetSourcePath();
+ info.args_sp = m_scripted_metadata->GetArgsSP();
+ }
+ m_registry_id = registry_sp->Add(std::move(info));
+ m_registry_wp = registry_sp;
+ }
+
StructuredData::GenericSP m_object_instance_sp;
std::optional<ScriptedMetadata> m_scripted_metadata;
+
+private:
+ void UnregisterInstance() {
+ // The interpreter owning the registry may already be gone.
+ if (auto registry_sp = m_registry_wp.lock())
+ registry_sp->Remove(m_registry_id);
+ m_registry_wp.reset();
+ }
+
+ lldb::ScriptedInstanceRegistryWP m_registry_wp;
+ uint64_t m_registry_id = 0;
};
} // namespace lldb_private
diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
index 7ad530b3233f2..eb25337e58194 100644
--- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h
+++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
@@ -22,11 +22,15 @@
#include "lldb/Interpreter/Interfaces/ScriptedProcessInterface.h"
#include "lldb/Interpreter/Interfaces/ScriptedThreadInterface.h"
#include "lldb/Interpreter/ScriptObject.h"
+#include "lldb/Interpreter/ScriptedInstanceRegistry.h"
#include "lldb/Utility/Broadcaster.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/StructuredData.h"
#include "lldb/Utility/UnimplementedError.h"
#include "lldb/lldb-private.h"
+#include "llvm/ADT/StringMap.h"
+#include <memory>
+#include <mutex>
#include <optional>
namespace lldb_private {
@@ -379,6 +383,15 @@ class ScriptInterpreter : public PluginInterface {
FileSpec extra_search_dir = {},
lldb::TargetSP loaded_into_target_sp = {});
+ void SetImportedModulePath(llvm::StringRef module_name, const FileSpec &path);
+
+ /// Falls back to the enclosing package for submodules of an imported one.
+ FileSpec GetImportedModulePath(llvm::StringRef module_name) const;
+
+ const lldb::ScriptedInstanceRegistrySP &GetScriptedInstanceRegistry() const {
+ return m_instance_registry_sp;
+ }
+
virtual bool IsReservedWord(const char *word) { return false; }
virtual std::unique_ptr<ScriptInterpreterLocker> AcquireInterpreterLock();
@@ -522,6 +535,12 @@ class ScriptInterpreter : public PluginInterface {
protected:
Debugger &m_debugger;
lldb::ScriptLanguage m_script_lang;
+
+private:
+ mutable std::mutex m_imported_modules_mutex;
+ llvm::StringMap<FileSpec> m_imported_modules;
+ lldb::ScriptedInstanceRegistrySP m_instance_registry_sp =
+ std::make_shared<ScriptedInstanceRegistry>();
};
} // namespace lldb_private
diff --git a/lldb/include/lldb/Interpreter/ScriptedInstanceRegistry.h b/lldb/include/lldb/Interpreter/ScriptedInstanceRegistry.h
new file mode 100644
index 0000000000000..f0c0fd1c9554d
--- /dev/null
+++ b/lldb/include/lldb/Interpreter/ScriptedInstanceRegistry.h
@@ -0,0 +1,97 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_INTERPRETER_SCRIPTEDINSTANCEREGISTRY_H
+#define LLDB_INTERPRETER_SCRIPTEDINSTANCEREGISTRY_H
+
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/Utility/UUID.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-types.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+
+#include <cstdint>
+#include <mutex>
+#include <string>
+#include <vector>
+
+namespace lldb_private {
+
+struct ScriptedInstanceInfo {
+ uint64_t id = 0;
+ UUID uuid;
+ lldb::addr_t object_address = LLDB_INVALID_ADDRESS;
+ /// Plugin names are string literals, so this never dangles.
+ llvm::StringRef plugin_name;
+ std::string class_name;
+ FileSpec source_path;
+ StructuredData::DictionarySP args_sp;
+};
+
+struct ScriptedInstanceGroup {
+ std::string class_name;
+ lldb::ScriptedExtension extension = lldb::eScriptedExtensionInvalid;
+ FileSpec source_path;
+ std::vector<ScriptedInstanceInfo> instances;
+
+ StructuredData::DictionarySP ToStructuredData() const;
+
+ void Dump(Stream &s, bool use_color) const;
+};
+
+/// Entries are snapshots taken when the object is created, so listing them
+/// never calls back into an interface that might be mid-destruction on
+/// another thread.
+class ScriptedInstanceRegistry {
+public:
+ uint64_t Add(ScriptedInstanceInfo info) {
+ std::lock_guard<std::mutex> guard(m_mutex);
+ const uint64_t id = m_next_id++;
+ info.id = id;
+ info.uuid = UUID::Generate();
+ m_instances[id] = std::move(info);
+ return id;
+ }
+
+ void Remove(uint64_t id) {
+ std::lock_guard<std::mutex> guard(m_mutex);
+ m_instances.erase(id);
+ }
+
+ std::vector<ScriptedInstanceInfo> GetInstances() const {
+ std::vector<ScriptedInstanceInfo> instances;
+ {
+ std::lock_guard<std::mutex> guard(m_mutex);
+ instances.reserve(m_instances.size());
+ for (const auto &entry : m_instances)
+ instances.push_back(entry.second);
+ }
+ llvm::sort(instances,
+ [](const ScriptedInstanceInfo &lhs,
+ const ScriptedInstanceInfo &rhs) { return lhs.id < rhs.id; });
+ return instances;
+ }
+
+ std::vector<ScriptedInstanceGroup> GetInstanceGroups(
+ llvm::ArrayRef<lldb::ScriptedExtension> extensions = {}) const;
+
+private:
+ mutable std::mutex m_mutex;
+ uint64_t m_next_id = 1;
+ llvm::DenseMap<uint64_t, ScriptedInstanceInfo> m_instances;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_INTERPRETER_SCRIPTEDINSTANCEREGISTRY_H
diff --git a/lldb/include/lldb/Utility/ScriptedMetadata.h b/lldb/include/lldb/Utility/ScriptedMetadata.h
index fcbcc70bc36e3..38dad813070c5 100644
--- a/lldb/include/lldb/Utility/ScriptedMetadata.h
+++ b/lldb/include/lldb/Utility/ScriptedMetadata.h
@@ -9,6 +9,7 @@
#ifndef LLDB_UTILITY_SCRIPTEDMETADATA_H
#define LLDB_UTILITY_SCRIPTEDMETADATA_H
+#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/ProcessInfo.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/StructuredData.h"
@@ -26,6 +27,7 @@ class ScriptedMetadata {
if (metadata_sp) {
m_class_name = metadata_sp->GetClassName();
m_args_sp = metadata_sp->GetArgsSP();
+ m_source_path = metadata_sp->GetSourcePath();
}
}
@@ -37,6 +39,11 @@ class ScriptedMetadata {
llvm::StringRef GetClassName() const { return m_class_name; }
StructuredData::DictionarySP GetArgsSP() const { return m_args_sp; }
+ const FileSpec &GetSourcePath() const { return m_source_path; }
+ void SetSourcePath(const FileSpec &source_path) {
+ m_source_path = source_path;
+ }
+
/// Get a unique identifier for this metadata based on its contents.
/// The ID is computed from the class name and arguments dictionary,
/// not from the pointer address, so two metadata objects with the same
@@ -62,6 +69,7 @@ class ScriptedMetadata {
private:
std::string m_class_name;
StructuredData::DictionarySP m_args_sp;
+ FileSpec m_source_path;
};
} // namespace lldb_private
diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h
index f48f077e9b5ee..649f7b704d68e 100644
--- a/lldb/include/lldb/lldb-forward.h
+++ b/lldb/include/lldb/lldb-forward.h
@@ -197,6 +197,7 @@ class ScriptedMetadata;
class ScriptedBreakpointInterface;
class ScriptedCommandInterface;
class ScriptedHookInterface;
+class ScriptedInstanceRegistry;
class ScriptedPlatformInterface;
class ScriptedProcessInterface;
class ScriptedThreadInterface;
@@ -436,6 +437,10 @@ typedef std::unique_ptr<lldb_private::ScriptedProcessInterface>
ScriptedProcessInterfaceUP;
typedef std::shared_ptr<lldb_private::ScriptedHookInterface>
ScriptedHookInterfaceSP;
+typedef std::shared_ptr<lldb_private::ScriptedInstanceRegistry>
+ ScriptedInstanceRegistrySP;
+typedef std::weak_ptr<lldb_private::ScriptedInstanceRegistry>
+ ScriptedInstanceRegistryWP;
typedef std::shared_ptr<lldb_private::ScriptedThreadInterface>
ScriptedThreadInterfaceSP;
typedef std::shared_ptr<lldb_private::ScriptedThreadPlanInterface>
diff --git a/lldb/source/Commands/CommandObjectScripting.cpp b/lldb/source/Commands/CommandObjectScripting.cpp
index 02c19ed4ef0cd..28eb1a8b80240 100644
--- a/lldb/source/Commands/CommandObjectScripting.cpp
+++ b/lldb/source/Commands/CommandObjectScripting.cpp
@@ -374,6 +374,118 @@ class CommandObjectScriptingExtensionList : public CommandObjectParsed {
CommandOptions m_options;
};
+#define LLDB_OPTIONS_scripting_extension_instances
+#include "CommandOptions.inc"
+
+class CommandObjectScriptingExtensionInstances : public CommandObjectParsed {
+public:
+ CommandObjectScriptingExtensionInstances(CommandInterpreter &interpreter)
+ : CommandObjectParsed(
+ interpreter, "scripting extension instances",
+ "List the instantiated scripting extensions, grouped by class, "
+ "along with the script file each class was imported from.",
+ "scripting extension instances [--json] [<extension-name> ...]") {
+ AddSimpleArgumentList(eArgTypeScriptedExtension, eArgRepeatStar);
+ }
+
+ ~CommandObjectScriptingExtensionInstances() override = default;
+
+ Options *GetOptions() override { return &m_options; }
+
+ void
+ HandleArgumentCompletion(CompletionRequest &request,
+ OptionElementVector &opt_element_vector) override {
+ lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
+ GetCommandInterpreter(), lldb::eScriptedExtensionCompletion, request,
+ nullptr);
+ }
+
+ class CommandOptions : public Options {
+ public:
+ CommandOptions() = default;
+ ~CommandOptions() override = default;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option) {
+ case 'j':
+ m_json_format = true;
+ break;
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+
+ return {};
+ }
+
+ void OptionParsingStarting(ExecutionContext *execution_context) override {
+ m_json_format = false;
+ }
+
+ llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
+ return llvm::ArrayRef(g_scripting_extension_instances_options);
+ }
+
+ bool m_json_format = false;
+ };
+
+protected:
+ void DoExecute(Args &command, CommandReturnObject &result) override {
+ std::vector<lldb::ScriptedExtension> extensions;
+ for (const Args::ArgEntry &arg : command.entries()) {
+ lldb::ScriptedExtension extension =
+ ScriptInterpreter::StringToExtension(arg.ref());
+ if (extension == eScriptedExtensionInvalid) {
+ result.AppendErrorWithFormat("no scripted extension named '%s'",
+ arg.c_str());
+ return;
+ }
+ extensions.push_back(extension);
+ }
+
+ std::vector<ScriptedInstanceGroup> groups;
+ if (ScriptInterpreter *script_interpreter =
+ GetDebugger().GetScriptInterpreter(/*can_create=*/false))
+ groups =
+ script_interpreter->GetScriptedInstanceRegistry()->GetInstanceGroups(
+ extensions);
+
+ if (m_options.m_json_format) {
+ StructuredData::Array groups_array;
+ for (const ScriptedInstanceGroup &group : groups)
+ groups_array.AddItem(group.ToStructuredData());
+ groups_array.Dump(result.GetOutputStream());
+ result.GetOutputStream().EOL();
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return;
+ }
+
+ Stream &s = result.GetOutputStream();
+ const bool use_color = s.AsRawOstream().colors_enabled();
+ constexpr llvm::StringLiteral faint_code = ANSI_ESCAPE1(ANSI_CTRL_FAINT);
+ constexpr llvm::StringLiteral reset_code = ANSI_ESCAPE1(ANSI_CTRL_NORMAL);
+ const std::string separator(
+ std::min<uint64_t>(GetDebugger().GetTerminalWidth(), 80), '-');
+
+ s.PutCString("Instantiated scripted extensions:");
+ if (groups.empty())
+ s << " None";
+ s.EOL();
+ for (const ScriptedInstanceGroup &group : groups) {
+ if (use_color)
+ s << faint_code << separator << reset_code << '\n';
+ else
+ s << separator << '\n';
+ group.Dump(s, use_color);
+ }
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+
+private:
+ CommandOptions m_options;
+};
+
#define LLDB_OPTIONS_scripting_extension_generate
#include "CommandOptions.inc"
@@ -576,6 +688,9 @@ class CommandObjectMultiwordScriptingExtension : public CommandObjectMultiword {
LoadSubCommand(
"list",
CommandObjectSP(new CommandObjectScriptingExtensionList(interpreter)));
+ LoadSubCommand("instances",
+ CommandObjectSP(new CommandObjectScriptingExtensionInstances(
+ interpreter)));
LoadSubCommand("generate",
CommandObjectSP(new CommandObjectScriptingExtensionGenerate(
interpreter)));
diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td
index ab851725979ef..9809d193ac258 100644
--- a/lldb/source/Commands/Options.td
+++ b/lldb/source/Commands/Options.td
@@ -1587,6 +1587,12 @@ let Command = "scripting extension list" in {
Desc<"Output the scripted extension list in json format.">;
}
+let Command = "scripting extension instances" in {
+ def scripting_extension_instances_json
+ : Option<"json", "j">,
+ Desc<"Output the instantiated scripted extensions in json format.">;
+}
+
let Command = "scripting extension generate" in {
def scripting_extension_generate_all_methods
: Option<"all", "a">,
diff --git a/lldb/source/Interpreter/CMakeLists.txt b/lldb/source/Interpreter/CMakeLists.txt
index 8a9605b568865..17290df85e2ec 100644
--- a/lldb/source/Interpreter/CMakeLists.txt
+++ b/lldb/source/Interpreter/CMakeLists.txt
@@ -58,6 +58,7 @@ add_lldb_library(lldbInterpreter NO_PLUGIN_DEPENDENCIES
Options.cpp
Property.cpp
ScriptInterpreter.cpp
+ ScriptedInstanceRegistry.cpp
ADDITIONAL_HEADER_DIRS
${LLDB_INCLUDE_DIR}/lldb/Interpreter
diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp
index a53f3b744f02e..0e402381b3a4e 100644
--- a/lldb/source/Interpreter/ScriptInterpreter.cpp
+++ b/lldb/source/Interpreter/ScriptInterpreter.cpp
@@ -65,6 +65,26 @@ bool ScriptInterpreter::LoadScriptingModule(
return false;
}
+void ScriptInterpreter::SetImportedModulePath(llvm::StringRef module_name,
+ const FileSpec &path) {
+ std::lock_guard<std::mutex> guard(m_imported_modules_mutex);
+ m_imported_modules[module_name] = path;
+}
+
+FileSpec
+ScriptInterpreter::GetImportedModulePath(llvm::StringRef module_name) const {
+ std::lock_guard<std::mutex> guard(m_imported_modules_mutex);
+ while (true) {
+ auto it = m_imported_modules.find(module_name);
+ if (it != m_imported_modules.end())
+ return it->second;
+ size_t dot_pos = module_name.rfind('.');
+ if (dot_pos == llvm::StringRef::npos)
+ return {};
+ module_name = module_name.take_front(dot_pos);
+ }
+}
+
std::string ScriptInterpreter::LanguageToString(lldb::ScriptLanguage language) {
switch (language) {
case eScriptLanguageNone:
diff --git a/lldb/source/Interpreter/ScriptedInstanceRegistry.cpp b/lldb/source/Interpreter/ScriptedInstanceRegistry.cpp
new file mode 100644
index 0000000000000..2ecfb1a0401be
--- /dev/null
+++ b/lldb/source/Interpreter/ScriptedInstanceRegistry.cpp
@@ -0,0 +1,153 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Interpreter/ScriptedInstanceRegistry.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Utility/AnsiTerminal.h"
+#include "lldb/Utility/Stream.h"
+
+#include "llvm/ADT/StringMap.h"
+
+#include <tuple>
+
+using namespace lldb;
+using namespace lldb_private;
+
+static bool HasArgs(const ScriptedInstanceInfo &info) {
+ return info.args_sp && info.args_sp->GetSize();
+}
+
+std::vector<ScriptedInstanceGroup> ScriptedInstanceRegistry::GetInstanceGroups(
+ llvm::ArrayRef<ScriptedExtension> extensions) const {
+ // Unknown names map to eScriptedExtensionInvalid, the zero value.
+ llvm::StringMap<ScriptedExtension> extension_by_plugin;
+ for (uint32_t i = 0; i < PluginManager::GetNumScriptedInterfaces(); i++)
+ extension_by_plugin[PluginManager::GetScriptedInterfaceNameAtIndex(i)] =
+ PluginManager::GetScriptedInterfaceExtensionAtIndex(i);
+
+ std::vector<ScriptedInstanceGroup> groups;
+ for (ScriptedInstanceInfo &info : GetInstances()) {
+ ScriptedExtension extension = extension_by_plugin.lookup(info.plugin_name);
+ if (!extensions.empty() && !llvm::is_contained(extensions, extension))
+ continue;
+
+ auto it = llvm::find_if(groups, [&](const ScriptedInstanceGroup &group) {
+ return group.class_name == info.class_name &&
+ group.source_path == info.source_path &&
+ group.extension == extension;
+ });
+ if (it == groups.end()) {
+ it = groups.insert(groups.end(), ScriptedInstanceGroup());
+ it->class_name = info.class_name;
+ it->extension = extension;
+ it->source_path = info.source_path;
+ }
+ it->instances.push_back(std::move(info));
+ }
+
+ llvm::sort(groups, [](const ScriptedInstanceGroup &lhs,
+ const ScriptedInstanceGroup &rhs) {
+ return std::make_tuple(llvm::StringRef(lhs.class_name),
+ lhs.source_path.GetPath(), lhs.extension) <
+ std::make_tuple(...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/226043
More information about the lldb-commits
mailing list