blob: 1e6cdf57815a2891711dd2e807b25a2324f79c2a [file] [edit]
//===----------------------------------------------------------------------===//
//
// 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/Debugger.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"
using namespace lldb;
using namespace lldb_private;
static bool HasArgs(const ScriptedInstanceInfo &info) {
return info.args_sp && info.args_sp->GetSize();
}
static bool CreatedBefore(const ScriptedInstanceInfo &lhs,
const ScriptedInstanceInfo &rhs) {
return lhs.id < rhs.id;
}
uint64_t ScriptedInstanceRegistry::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 ScriptedInstanceRegistry::Remove(uint64_t id) {
std::lock_guard<std::mutex> guard(m_mutex);
m_instances.erase(id);
}
std::vector<ScriptedInstanceInfo>
ScriptedInstanceRegistry::CopyInstances() const {
std::lock_guard<std::mutex> guard(m_mutex);
std::vector<ScriptedInstanceInfo> instances;
instances.reserve(m_instances.size());
for (const auto &entry : m_instances)
instances.push_back(entry.second);
return instances;
}
std::vector<ScriptedInstanceInfo>
ScriptedInstanceRegistry::GetInstances() const {
std::vector<ScriptedInstanceInfo> instances = CopyInstances();
llvm::sort(instances, CreatedBefore);
return instances;
}
bool ScriptedInstanceGroup::operator<(
const ScriptedInstanceGroup &other) const {
if (class_name != other.class_name)
return class_name < other.class_name;
const std::string path = source_path.GetPath();
const std::string other_path = other.source_path.GetPath();
if (path != other_path)
return path < other_path;
return extension < other.extension;
}
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 (size_t i = 0; i < PluginManager::GetNumScriptedInterfaces(); i++)
extension_by_plugin[PluginManager::GetScriptedInterfaceNameAtIndex(i)] =
PluginManager::GetScriptedInterfaceExtensionAtIndex(i);
std::vector<ScriptedInstanceGroup> groups;
for (ScriptedInstanceInfo &info : CopyInstances()) {
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));
}
for (ScriptedInstanceGroup &group : groups)
llvm::sort(group.instances, CreatedBefore);
llvm::sort(groups);
return groups;
}
StructuredData::DictionarySP ScriptedInstanceGroup::ToStructuredData() const {
auto group_sp = std::make_shared<StructuredData::Dictionary>();
group_sp->AddStringItem("class_name", class_name);
group_sp->AddStringItem("extension",
ScriptInterpreter::ExtensionToString(extension));
if (source_path)
group_sp->AddStringItem("source_path", source_path.GetPath());
auto instances_sp = std::make_shared<StructuredData::Array>();
for (const ScriptedInstanceInfo &info : instances) {
auto instance_sp = std::make_shared<StructuredData::Dictionary>();
instance_sp->AddStringItem("uuid", info.uuid.GetAsString());
if (info.object_address != LLDB_INVALID_ADDRESS)
instance_sp->AddIntegerItem("address", info.object_address);
if (HasArgs(info))
instance_sp->AddItem("args", info.args_sp);
instances_sp->AddItem(instance_sp);
}
group_sp->AddItem("instances", instances_sp);
return group_sp;
}
void ScriptedInstanceGroup::Dump(Stream &s, const Debugger &debugger,
bool use_color) const {
auto ansi_code = [use_color](llvm::StringRef code) {
return ansi::FormatAnsiTerminalCodes(code, use_color);
};
const std::string label_prefix = ansi_code(debugger.GetLabelAnsiPrefix());
const std::string label_suffix = ansi_code(debugger.GetLabelAnsiSuffix());
const std::string title_prefix = ansi_code(debugger.GetTitleAnsiPrefix());
const std::string title_suffix = ansi_code(debugger.GetTitleAnsiSuffix());
auto print_label = [&](llvm::StringRef indent, llvm::StringRef label) {
s << indent << label_prefix << label << ':' << label_suffix;
};
auto print_instance = [&](const ScriptedInstanceInfo &info) {
s << info.uuid.GetAsString();
if (info.object_address != LLDB_INVALID_ADDRESS)
s.Format(" ({0:x})", info.object_address);
s << '\n';
};
auto print_args = [&](const ScriptedInstanceInfo &info,
llvm::StringRef indent) {
if (!HasArgs(info))
return;
print_label(indent, "Args");
s << '\n';
info.args_sp->ForEachSorted(
[&](llvm::StringRef key, StructuredData::Object *value) {
s << indent << " - " << key << ": ";
if (StructuredData::String *str = value->GetAsString())
s << str->GetValue();
else
value->Dump(s, /*pretty_print=*/false);
s << '\n';
return true;
});
};
print_label(" ", "Class");
s << ' ' << title_prefix << class_name << title_suffix << '\n';
print_label(" ", "Extension");
s << ' ' << ScriptInterpreter::ExtensionToString(extension) << '\n';
if (source_path) {
print_label(" ", "Path");
s << ' ' << source_path.GetPath() << '\n';
}
if (instances.size() == 1) {
print_label(" ", "Instance");
s << ' ';
print_instance(instances.front());
print_args(instances.front(), " ");
return;
}
print_label(" ", "Instances");
s << '\n';
for (auto [idx, info] : llvm::enumerate(instances)) {
s.Format(" [{0}] ", idx);
print_instance(info);
print_args(info, " ");
}
}