[Lldb-commits] [lldb] [lldb/script] Add class-based summary providers via ScriptedStringSummaryInterface (PR #210469)
Med Ismail Bennani via lldb-commits
lldb-commits at lists.llvm.org
Tue Jul 28 00:10:49 PDT 2026
https://github.com/medismailben updated https://github.com/llvm/llvm-project/pull/210469
>From 720badbd79729c02a386b12eb8172efab5e78998 Mon Sep 17 00:00:00 2001
From: Med Ismail Bennani <ismail at bennani.ma>
Date: Tue, 28 Jul 2026 00:09:19 -0700
Subject: [PATCH] [lldb] Add class-based summary providers via
ScriptedStringSummaryInterface
Add `type summary add -L <ClassName>` as a class-based alternative to the
existing function-based summary providers, purely additive: nothing about
ScriptSummaryFormat/GetScriptedSummary (the existing function-based path) is
touched.
ScriptedSummaryFormat (TypeSummary.h/.cpp) is a new TypeSummaryImpl backed by
a new Kind::eScriptedClass, parallel to ScriptSummaryFormat. Unlike every
other scripted extension in this series, its interface object cannot be
created eagerly at construction time -- SBTypeSummary::CreateWithClassName
can run before any debugger/target context exists -- so CreatePluginObject is
deferred to the first FormatObject() call and cached from then on, mirroring
how ScriptSummaryFormat already lazily resolves and caches its function
object.
SBTypeSummary::CreateWithClassName mirrors SBTypeSynthetic::CreateWithClassName's
existing shape. The two exhaustive switches over TypeSummaryImpl::Kind
(GetSummaryKindName, SBTypeSummary::IsEqualTo) each get a case for
eScriptedClass so the new kind does not trip a -Wswitch failure or silently
compare unequal.
Signed-off-by: Med Ismail Bennani <ismail at bennani.ma>
---
lldb/bindings/python/CMakeLists.txt | 1 +
lldb/docs/CMakeLists.txt | 1 +
.../templates/scripted_string_summary.py | 40 ++++++++++
lldb/include/lldb/API/SBTypeSummary.h | 4 +
.../include/lldb/DataFormatters/TypeSummary.h | 54 ++++++++++++-
.../ScriptedStringSummaryInterface.h | 28 +++++++
.../lldb/Interpreter/ScriptInterpreter.h | 5 ++
lldb/include/lldb/lldb-enumerations.h | 3 +-
lldb/include/lldb/lldb-forward.h | 3 +
lldb/source/API/SBTypeSummary.cpp | 25 +++++++
lldb/source/Commands/CommandObjectType.cpp | 72 ++++++++++++++++--
lldb/source/DataFormatters/TypeSummary.cpp | 75 +++++++++++++++++++
lldb/source/Interpreter/ScriptInterpreter.cpp | 4 +
.../ScriptInterpreter/Python/CMakeLists.txt | 1 +
.../ScriptInterpreterPythonInterfaces.cpp | 2 +
.../ScriptInterpreterPythonInterfaces.h | 1 +
.../Interfaces/ScriptedPythonInterface.h | 12 +++
.../ScriptedStringSummaryPythonInterface.cpp | 61 +++++++++++++++
.../ScriptedStringSummaryPythonInterface.h | 48 ++++++++++++
.../Python/ScriptInterpreterPython.cpp | 7 ++
.../Python/ScriptInterpreterPythonImpl.h | 3 +
21 files changed, 442 insertions(+), 8 deletions(-)
create mode 100644 lldb/examples/python/templates/scripted_string_summary.py
create mode 100644 lldb/include/lldb/Interpreter/Interfaces/ScriptedStringSummaryInterface.h
create mode 100644 lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStringSummaryPythonInterface.cpp
create mode 100644 lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStringSummaryPythonInterface.h
diff --git a/lldb/bindings/python/CMakeLists.txt b/lldb/bindings/python/CMakeLists.txt
index d29b143c1408c..902f20d4f0b41 100644
--- a/lldb/bindings/python/CMakeLists.txt
+++ b/lldb/bindings/python/CMakeLists.txt
@@ -120,6 +120,7 @@ function(finish_swig_python swig_target lldb_python_bindings_dir lldb_python_tar
"${LLDB_SOURCE_DIR}/examples/python/templates/scripted_breakpoint.py"
"${LLDB_SOURCE_DIR}/examples/python/templates/scripted_hook.py"
"${LLDB_SOURCE_DIR}/examples/python/templates/scripted_stackframe_recognizer.py"
+ "${LLDB_SOURCE_DIR}/examples/python/templates/scripted_string_summary.py"
)
if(APPLE)
diff --git a/lldb/docs/CMakeLists.txt b/lldb/docs/CMakeLists.txt
index dd091836dc1aa..760991c5a68b5 100644
--- a/lldb/docs/CMakeLists.txt
+++ b/lldb/docs/CMakeLists.txt
@@ -33,6 +33,7 @@ if (LLDB_ENABLE_PYTHON AND SPHINX_FOUND)
COMMAND "${CMAKE_COMMAND}" -E copy "${LLDB_SOURCE_DIR}/examples/python/templates/scripted_breakpoint.py" "${CMAKE_CURRENT_BINARY_DIR}/lldb/plugins/"
COMMAND "${CMAKE_COMMAND}" -E copy "${LLDB_SOURCE_DIR}/examples/python/templates/scripted_hook.py" "${CMAKE_CURRENT_BINARY_DIR}/lldb/plugins/"
COMMAND "${CMAKE_COMMAND}" -E copy "${LLDB_SOURCE_DIR}/examples/python/templates/scripted_stackframe_recognizer.py" "${CMAKE_CURRENT_BINARY_DIR}/lldb/plugins/"
+ COMMAND "${CMAKE_COMMAND}" -E copy "${LLDB_SOURCE_DIR}/examples/python/templates/scripted_string_summary.py" "${CMAKE_CURRENT_BINARY_DIR}/lldb/plugins/"
COMMENT "Copying lldb.py to pretend its a Python package.")
add_dependencies(lldb-python-doc-package swig_wrapper_python)
diff --git a/lldb/examples/python/templates/scripted_string_summary.py b/lldb/examples/python/templates/scripted_string_summary.py
new file mode 100644
index 0000000000000..217c3bb6a8e25
--- /dev/null
+++ b/lldb/examples/python/templates/scripted_string_summary.py
@@ -0,0 +1,40 @@
+from abc import ABCMeta, abstractmethod
+
+import lldb
+
+
+class ScriptedStringSummary(metaclass=ABCMeta):
+ """
+ The base class for a scripted string summary provider.
+
+ A summary provider produces the one-line string shown next to a value in
+ `frame variable`/`expression` output. Register it with
+ `type summary add -l <ClassName> <TypeName>`.
+
+ Most of the base class methods are `@abstractmethod` that need to be
+ overwritten by the inheriting class.
+ """
+
+ def __init__(self):
+ """Construct a scripted summary provider.
+
+ Summary providers are constructed with no arguments and are shared
+ across every value they're asked to summarize.
+ """
+ pass
+
+ @abstractmethod
+ def get_summary(
+ self, valobj: lldb.SBValue, options: lldb.SBTypeSummaryOptions
+ ) -> str:
+ """Get the summary string for a value.
+
+ Args:
+ valobj (lldb.SBValue): The value to summarize.
+ options (lldb.SBTypeSummaryOptions): The options to use when
+ producing the summary.
+
+ Returns:
+ str: The summary string for `valobj`.
+ """
+ pass
diff --git a/lldb/include/lldb/API/SBTypeSummary.h b/lldb/include/lldb/API/SBTypeSummary.h
index b6869e53a39e7..9ca26532d8156 100644
--- a/lldb/include/lldb/API/SBTypeSummary.h
+++ b/lldb/include/lldb/API/SBTypeSummary.h
@@ -81,6 +81,10 @@ class SBTypeSummary {
CreateWithScriptCode(const char *data,
uint32_t options = 0); // see lldb::eTypeOption values
+ static SBTypeSummary
+ CreateWithClassName(const char *data,
+ uint32_t options = 0); // see lldb::eTypeOption values
+
#ifndef SWIG
static SBTypeSummary CreateWithCallback(FormatCallback cb,
uint32_t options = 0,
diff --git a/lldb/include/lldb/DataFormatters/TypeSummary.h b/lldb/include/lldb/DataFormatters/TypeSummary.h
index a0938556e0174..4abf18c9c39a3 100644
--- a/lldb/include/lldb/DataFormatters/TypeSummary.h
+++ b/lldb/include/lldb/DataFormatters/TypeSummary.h
@@ -48,7 +48,14 @@ class TypeSummaryOptions {
class TypeSummaryImpl {
public:
- enum class Kind { eSummaryString, eScript, eBytecode, eCallback, eInternal };
+ enum class Kind {
+ eSummaryString,
+ eScript,
+ eBytecode,
+ eCallback,
+ eInternal,
+ eScriptedClass
+ };
virtual ~TypeSummaryImpl() = default;
@@ -423,6 +430,51 @@ struct ScriptSummaryFormat : public TypeSummaryImpl {
const ScriptSummaryFormat &operator=(const ScriptSummaryFormat &) = delete;
};
+// Python-based summaries backed by a class, running an instance's
+// `get_summary` method to show data. Unlike ScriptSummaryFormat (a bare
+// function resolved once and cached), the Python object here is itself the
+// cache: it's created lazily on the first call to FormatObject (since this
+// format can be constructed via SBTypeSummary::CreateWithClassName before
+// any debugger/target context exists) and then reused across every
+// subsequent call, for every value of the matching type.
+struct ScriptedSummaryFormat : public TypeSummaryImpl {
+ std::string m_class_name;
+ lldb::ScriptedStringSummaryInterfaceSP m_interface_sp;
+
+ ScriptedSummaryFormat(const TypeSummaryImpl::Flags &flags,
+ const char *class_name, uint32_t ptr_match_depth = 1);
+
+ ~ScriptedSummaryFormat() override = default;
+
+ const char *GetClassName() const { return m_class_name.c_str(); }
+
+ void SetClassName(const char *class_name) {
+ if (class_name)
+ m_class_name.assign(class_name);
+ else
+ m_class_name.clear();
+ m_interface_sp.reset();
+ }
+
+ bool FormatObject(ValueObject *valobj, std::string &dest,
+ const TypeSummaryOptions &options) override;
+
+ std::string GetDescription() override;
+
+ std::string GetName() override;
+
+ static bool classof(const TypeSummaryImpl *S) {
+ return S->GetKind() == Kind::eScriptedClass;
+ }
+
+ typedef std::shared_ptr<ScriptedSummaryFormat> SharedPointer;
+
+private:
+ ScriptedSummaryFormat(const ScriptedSummaryFormat &) = delete;
+ const ScriptedSummaryFormat &
+ operator=(const ScriptedSummaryFormat &) = delete;
+};
+
/// A summary formatter that is defined in LLDB formmater bytecode.
///
/// See `BytecodeSyntheticChildren` for the corresponding synthetic formatter.
diff --git a/lldb/include/lldb/Interpreter/Interfaces/ScriptedStringSummaryInterface.h b/lldb/include/lldb/Interpreter/Interfaces/ScriptedStringSummaryInterface.h
new file mode 100644
index 0000000000000..83f1822823005
--- /dev/null
+++ b/lldb/include/lldb/Interpreter/Interfaces/ScriptedStringSummaryInterface.h
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_INTERFACES_SCRIPTEDSTRINGSUMMARYINTERFACE_H
+#define LLDB_INTERPRETER_INTERFACES_SCRIPTEDSTRINGSUMMARYINTERFACE_H
+
+#include "ScriptedInterface.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+class ScriptedStringSummaryInterface : virtual public ScriptedInterface {
+public:
+ virtual llvm::Expected<StructuredData::GenericSP>
+ CreatePluginObject(llvm::StringRef class_name) = 0;
+
+ virtual llvm::Expected<std::string>
+ GetSummary(ValueObject &valobj, const TypeSummaryOptions &options) {
+ return llvm::createStringError("not implemented");
+ }
+};
+} // namespace lldb_private
+
+#endif // LLDB_INTERPRETER_INTERFACES_SCRIPTEDSTRINGSUMMARYINTERFACE_H
diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
index 0e65cb4b8ac4a..98ff3a353d405 100644
--- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h
+++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
@@ -586,6 +586,11 @@ class ScriptInterpreter : public PluginInterface {
return {};
}
+ virtual lldb::ScriptedStringSummaryInterfaceSP
+ CreateScriptedStringSummaryInterface() {
+ return {};
+ }
+
virtual StructuredData::ObjectSP
CreateStructuredDataFromScriptObject(ScriptObject obj) {
return {};
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index 93c252b55de99..773152d1dc13b 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -268,7 +268,8 @@ enum ScriptedExtension {
eScriptedExtensionScriptedThread,
eScriptedExtensionScriptedFrame,
eScriptedExtensionScriptedStackFrameRecognizer,
- kLastScriptedExtension = eScriptedExtensionScriptedStackFrameRecognizer
+ eScriptedExtensionScriptedStringSummary,
+ kLastScriptedExtension = eScriptedExtensionScriptedStringSummary
};
/// Register numbering types.
diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h
index 157aa5743f016..075a033253b1c 100644
--- a/lldb/include/lldb/lldb-forward.h
+++ b/lldb/include/lldb/lldb-forward.h
@@ -199,6 +199,7 @@ class ScriptedProcessInterface;
class ScriptedThreadInterface;
class ScriptedThreadPlanInterface;
class ScriptedStackFrameRecognizerInterface;
+class ScriptedStringSummaryInterface;
class ScriptedSyntheticChildren;
class SearchFilter;
class Section;
@@ -438,6 +439,8 @@ typedef std::shared_ptr<lldb_private::ScriptedBreakpointInterface>
ScriptedBreakpointInterfaceSP;
typedef std::shared_ptr<lldb_private::ScriptedStackFrameRecognizerInterface>
ScriptedStackFrameRecognizerInterfaceSP;
+typedef std::shared_ptr<lldb_private::ScriptedStringSummaryInterface>
+ ScriptedStringSummaryInterfaceSP;
typedef std::shared_ptr<lldb_private::Section> SectionSP;
typedef std::unique_ptr<lldb_private::SectionList> SectionListUP;
typedef std::weak_ptr<lldb_private::Section> SectionWP;
diff --git a/lldb/source/API/SBTypeSummary.cpp b/lldb/source/API/SBTypeSummary.cpp
index 58ec068ab9600..a424394d2768f 100644
--- a/lldb/source/API/SBTypeSummary.cpp
+++ b/lldb/source/API/SBTypeSummary.cpp
@@ -135,6 +135,17 @@ SBTypeSummary SBTypeSummary::CreateWithScriptCode(const char *data,
TypeSummaryImplSP(new ScriptSummaryFormat(options, "", data)));
}
+SBTypeSummary SBTypeSummary::CreateWithClassName(const char *data,
+ uint32_t options) {
+ LLDB_INSTRUMENT_VA(data, options);
+
+ if (!data || data[0] == 0)
+ return SBTypeSummary();
+
+ return SBTypeSummary(
+ TypeSummaryImplSP(new ScriptedSummaryFormat(options, data)));
+}
+
SBTypeSummary SBTypeSummary::CreateWithCallback(FormatCallback cb,
uint32_t options,
const char *description) {
@@ -372,6 +383,16 @@ bool SBTypeSummary::IsEqualTo(lldb::SBTypeSummary &rhs) {
return GetOptions() == rhs.GetOptions();
case TypeSummaryImpl::Kind::eInternal:
return (m_opaque_sp.get() == rhs.m_opaque_sp.get());
+ case TypeSummaryImpl::Kind::eScriptedClass: {
+ ScriptedSummaryFormat *lhs_ptr =
+ llvm::dyn_cast<ScriptedSummaryFormat>(m_opaque_sp.get());
+ ScriptedSummaryFormat *rhs_ptr =
+ llvm::dyn_cast<ScriptedSummaryFormat>(rhs.m_opaque_sp.get());
+ if (!lhs_ptr || !rhs_ptr)
+ return false;
+ return strcmp(lhs_ptr->GetClassName(), rhs_ptr->GetClassName()) == 0 &&
+ GetOptions() == rhs.GetOptions();
+ }
}
return false;
@@ -417,6 +438,10 @@ bool SBTypeSummary::CopyOnWrite_Impl() {
llvm::dyn_cast<StringSummaryFormat>(m_opaque_sp.get())) {
new_sp = TypeSummaryImplSP(new StringSummaryFormat(
GetOptions(), current_summary_ptr->GetSummaryString()));
+ } else if (ScriptedSummaryFormat *current_summary_ptr =
+ llvm::dyn_cast<ScriptedSummaryFormat>(m_opaque_sp.get())) {
+ new_sp = TypeSummaryImplSP(new ScriptedSummaryFormat(
+ GetOptions(), current_summary_ptr->GetClassName()));
}
SetSP(new_sp);
diff --git a/lldb/source/Commands/CommandObjectType.cpp b/lldb/source/Commands/CommandObjectType.cpp
index 8a0fdd677b4fc..d5312635acf94 100644
--- a/lldb/source/Commands/CommandObjectType.cpp
+++ b/lldb/source/Commands/CommandObjectType.cpp
@@ -21,6 +21,7 @@
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/OptionArgParser.h"
#include "lldb/Interpreter/OptionGroupFormat.h"
+#include "lldb/Interpreter/OptionGroupPythonClassWithDict.h"
#include "lldb/Interpreter/OptionValueBoolean.h"
#include "lldb/Interpreter/OptionValueLanguage.h"
#include "lldb/Interpreter/OptionValueString.h"
@@ -123,9 +124,9 @@ const char *FormatCategoryToString(FormatCategoryItem item, bool long_name) {
class CommandObjectTypeSummaryAdd : public CommandObjectParsed,
public IOHandlerDelegateMultiline {
private:
- class CommandOptions : public Options {
+ class CommandOptions : public OptionGroup {
public:
- CommandOptions(CommandInterpreter &interpreter) {}
+ CommandOptions() = default;
~CommandOptions() override = default;
@@ -151,12 +152,16 @@ class CommandObjectTypeSummaryAdd : public CommandObjectParsed,
uint32_t m_ptr_match_depth = 1;
};
+ OptionGroupOptions m_option_group;
CommandOptions m_options;
+ OptionGroupPythonClassWithDict m_class_options;
- Options *GetOptions() override { return &m_options; }
+ Options *GetOptions() override { return &m_option_group; }
bool Execute_ScriptSummary(Args &command, CommandReturnObject &result);
+ bool Execute_PythonClassSummary(Args &command, CommandReturnObject &result);
+
bool Execute_StringSummary(Args &command, CommandReturnObject &result);
public:
@@ -1164,7 +1169,7 @@ Status CommandObjectTypeSummaryAdd::CommandOptions::SetOptionValue(
uint32_t option_idx, llvm::StringRef option_arg,
ExecutionContext *execution_context) {
Status error;
- const int short_option = m_getopt_table[option_idx].val;
+ const int short_option = g_type_summary_add_options[option_idx].short_option;
bool success;
switch (short_option) {
@@ -1375,6 +1380,48 @@ bool CommandObjectTypeSummaryAdd::Execute_ScriptSummary(
return result.Succeeded();
}
+bool CommandObjectTypeSummaryAdd::Execute_PythonClassSummary(
+ Args &command, CommandReturnObject &result) {
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc < 1 && !m_options.m_name) {
+ result.AppendErrorWithFormat("%s takes one or more args",
+ m_cmd_name.c_str());
+ return false;
+ }
+
+ const std::string &class_name = m_class_options.GetName();
+ if (class_name.empty()) {
+ result.AppendError("must provide a Python class name");
+ return false;
+ }
+
+ TypeSummaryImplSP script_format = std::make_shared<ScriptedSummaryFormat>(
+ m_options.m_flags, class_name.c_str(), m_options.m_ptr_match_depth);
+
+ Status error;
+
+ for (auto &entry : command.entries()) {
+ AddSummary(ConstString(entry.ref()), script_format, m_options.m_match_type,
+ m_options.m_category, &error);
+ if (error.Fail()) {
+ result.AppendError(error.AsCString());
+ return false;
+ }
+ }
+
+ if (m_options.m_name) {
+ AddNamedSummary(m_options.m_name, script_format, &error);
+ if (error.Fail()) {
+ result.AppendError(error.AsCString());
+ result.AppendError("added to types, but not given a name");
+ return false;
+ }
+ }
+
+ return result.Succeeded();
+}
+
#endif
bool CommandObjectTypeSummaryAdd::Execute_StringSummary(
@@ -1451,7 +1498,14 @@ CommandObjectTypeSummaryAdd::CommandObjectTypeSummaryAdd(
CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "type summary add",
"Add a new summary style for a type.", nullptr),
- IOHandlerDelegateMultiline("DONE"), m_options(interpreter) {
+ IOHandlerDelegateMultiline("DONE"),
+ m_class_options("scripted string summary", /*is_class=*/true, 'L', 'K',
+ 'V', /*required_options=*/0) {
+ m_option_group.Append(&m_options);
+ m_option_group.Append(&m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2,
+ LLDB_OPT_SET_ALL);
+ m_option_group.Finalize();
+
AddSimpleArgumentList(eArgTypeName, eArgRepeatPlus);
SetHelpLong(
@@ -1554,7 +1608,13 @@ void CommandObjectTypeSummaryAdd::DoExecute(Args &command,
CommandReturnObject &result) {
WarnOnPotentialUnquotedUnsignedType(command, result);
- if (m_options.m_is_add_script) {
+ if (!m_class_options.GetName().empty()) {
+#if LLDB_ENABLE_PYTHON
+ Execute_PythonClassSummary(command, result);
+#else
+ result.AppendError("python is disabled");
+#endif
+ } else if (m_options.m_is_add_script) {
#if LLDB_ENABLE_PYTHON
Execute_ScriptSummary(command, result);
#else
diff --git a/lldb/source/DataFormatters/TypeSummary.cpp b/lldb/source/DataFormatters/TypeSummary.cpp
index 4f01466f85148..73691bb53570f 100644
--- a/lldb/source/DataFormatters/TypeSummary.cpp
+++ b/lldb/source/DataFormatters/TypeSummary.cpp
@@ -16,6 +16,8 @@
#include "lldb/Core/Debugger.h"
#include "lldb/DataFormatters/ValueObjectPrinter.h"
#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/Interfaces/ScriptedStringSummaryInterface.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
@@ -60,6 +62,8 @@ std::string TypeSummaryImpl::GetSummaryKindName() {
return "c++";
case Kind::eBytecode:
return "bytecode";
+ case Kind::eScriptedClass:
+ return "python class";
}
llvm_unreachable("Unknown type kind name");
}
@@ -242,6 +246,77 @@ std::string ScriptSummaryFormat::GetDescription() {
std::string ScriptSummaryFormat::GetName() { return m_script_formatter_name; }
+ScriptedSummaryFormat::ScriptedSummaryFormat(
+ const TypeSummaryImpl::Flags &flags, const char *class_name,
+ uint32_t ptr_match_depth)
+ : TypeSummaryImpl(Kind::eScriptedClass, flags, ptr_match_depth),
+ m_class_name(class_name ? class_name : ""), m_interface_sp() {}
+
+bool ScriptedSummaryFormat::FormatObject(ValueObject *valobj,
+ std::string &retval,
+ const TypeSummaryOptions &options) {
+ if (!valobj)
+ return false;
+
+ TargetSP target_sp(valobj->GetTargetSP());
+
+ if (!target_sp) {
+ retval.assign("error: no target");
+ return false;
+ }
+
+ ScriptInterpreter *script_interpreter =
+ target_sp->GetDebugger().GetScriptInterpreter();
+
+ if (!script_interpreter) {
+ retval.assign("error: no ScriptInterpreter");
+ return false;
+ }
+
+ if (!m_interface_sp) {
+ m_interface_sp = script_interpreter->CreateScriptedStringSummaryInterface();
+ if (!m_interface_sp) {
+ retval.assign("error: no ScriptedStringSummaryInterface");
+ return false;
+ }
+
+ llvm::Expected<StructuredData::GenericSP> obj_or_err =
+ m_interface_sp->CreatePluginObject(m_class_name);
+ if (!obj_or_err) {
+ retval.assign(llvm::toString(obj_or_err.takeError()));
+ m_interface_sp.reset();
+ return false;
+ }
+ }
+
+ llvm::Expected<std::string> summary =
+ m_interface_sp->GetSummary(*valobj, options);
+ if (!summary) {
+ retval.assign(llvm::toString(summary.takeError()));
+ return false;
+ }
+
+ retval = std::move(*summary);
+ return true;
+}
+
+std::string ScriptedSummaryFormat::GetDescription() {
+ StreamString sstr;
+ sstr.Printf("%s%s%s%s%s%s%s ptr-match-depth=%u\n ",
+ Cascades() ? "" : " (not cascading)",
+ !DoesPrintChildren(nullptr) ? "" : " (show children)",
+ !DoesPrintValue(nullptr) ? " (hide value)" : "",
+ IsOneLiner() ? " (one-line printout)" : "",
+ SkipsPointers() ? " (skip pointers)" : "",
+ SkipsReferences() ? " (skip references)" : "",
+ HideNames(nullptr) ? " (hide member names)" : "",
+ GetPtrMatchDepth());
+ sstr.PutCString(m_class_name);
+ return std::string(sstr.GetString());
+}
+
+std::string ScriptedSummaryFormat::GetName() { return m_class_name; }
+
BytecodeSummaryFormat::BytecodeSummaryFormat(
const TypeSummaryImpl::Flags &flags,
std::unique_ptr<llvm::MemoryBuffer> bytecode)
diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp
index 4f6095d097d10..33e915951596e 100644
--- a/lldb/source/Interpreter/ScriptInterpreter.cpp
+++ b/lldb/source/Interpreter/ScriptInterpreter.cpp
@@ -221,6 +221,8 @@ ScriptInterpreter::ExtensionToString(lldb::ScriptedExtension extension) {
return "ScriptedFrame";
case eScriptedExtensionScriptedStackFrameRecognizer:
return "ScriptedStackFrameRecognizer";
+ case eScriptedExtensionScriptedStringSummary:
+ return "ScriptedStringSummary";
}
llvm_unreachable("unhandled ScriptedExtension");
}
@@ -241,6 +243,8 @@ ScriptInterpreter::StringToExtension(llvm::StringRef string) {
.CaseLower("ScriptedFrame", eScriptedExtensionScriptedFrame)
.CaseLower("ScriptedStackFrameRecognizer",
eScriptedExtensionScriptedStackFrameRecognizer)
+ .CaseLower("ScriptedStringSummary",
+ eScriptedExtensionScriptedStringSummary)
.Default(eScriptedExtensionInvalid);
}
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
index 201574da72a19..9932d31d26f30 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
@@ -33,6 +33,7 @@ set(python_plugin_sources
Interfaces/ScriptedHookPythonInterface.cpp
Interfaces/ScriptedBreakpointPythonInterface.cpp
Interfaces/ScriptedStackFrameRecognizerPythonInterface.cpp
+ Interfaces/ScriptedStringSummaryPythonInterface.cpp
Interfaces/ScriptedThreadPlanPythonInterface.cpp
Interfaces/ScriptedThreadPythonInterface.cpp
)
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp
index 8914f6b239023..1636723a7d459 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp
@@ -30,6 +30,7 @@ void ScriptInterpreterPythonInterfaces::Initialize() {
ScriptedThreadPythonInterface::Initialize();
ScriptedFramePythonInterface::Initialize();
ScriptedStackFrameRecognizerPythonInterface::Initialize();
+ ScriptedStringSummaryPythonInterface::Initialize();
}
void ScriptInterpreterPythonInterfaces::Terminate() {
@@ -43,4 +44,5 @@ void ScriptInterpreterPythonInterfaces::Terminate() {
ScriptedThreadPythonInterface::Terminate();
ScriptedFramePythonInterface::Terminate();
ScriptedStackFrameRecognizerPythonInterface::Terminate();
+ ScriptedStringSummaryPythonInterface::Terminate();
}
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h
index 03d747e63a592..686614c5f2da9 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h
@@ -20,6 +20,7 @@
#include "ScriptedPlatformPythonInterface.h"
#include "ScriptedProcessPythonInterface.h"
#include "ScriptedStackFrameRecognizerPythonInterface.h"
+#include "ScriptedStringSummaryPythonInterface.h"
#include "ScriptedThreadPlanPythonInterface.h"
#include "ScriptedThreadPythonInterface.h"
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
index aaa0b6a0f7a59..ba448da93185e 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
@@ -668,6 +668,10 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
return python::SWIGBridge::ToSWIGWrapper(arg);
}
+ python::PythonObject Transform(const TypeSummaryOptions &arg) {
+ return python::SWIGBridge::ToSWIGWrapper(arg);
+ }
+
template <typename T, typename U>
void ReverseTransform(T &original_arg, U transformed_arg, Status &error) {
// If U is not a PythonObject, don't touch it!
@@ -679,6 +683,14 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
original_arg = ExtractValueFromPythonObject<T>(transformed_arg, error);
}
+ // Read-only arguments (passed as `const T&`) have nothing to write back:
+ // there's no `T` value to reassign into a const reference, and no
+ // `ExtractValueFromPythonObject<T>` specialization should be required just
+ // to satisfy this round-trip for a value the callee never mutates.
+ template <typename T>
+ void ReverseTransform(const T &original_arg,
+ python::PythonObject transformed_arg, Status &error) {}
+
void ReverseTransform(bool &original_arg,
python::PythonObject transformed_arg, Status &error) {
python::PythonBoolean boolean_arg = python::PythonBoolean(
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStringSummaryPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStringSummaryPythonInterface.cpp
new file mode 100644
index 0000000000000..b0efa7615af96
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStringSummaryPythonInterface.cpp
@@ -0,0 +1,61 @@
+//===----------------------------------------------------------------------===//
+//
+// 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-python.h"
+
+#include "lldb/Core/PluginManager.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/ValueObject/ValueObject.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "../ScriptInterpreterPythonImpl.h"
+#include "ScriptedStringSummaryPythonInterface.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ScriptedStringSummaryPythonInterface::ScriptedStringSummaryPythonInterface(
+ ScriptInterpreterPythonImpl &interpreter)
+ : ScriptedStringSummaryInterface(), ScriptedPythonInterface(interpreter) {}
+
+llvm::Expected<StructuredData::GenericSP>
+ScriptedStringSummaryPythonInterface::CreatePluginObject(
+ llvm::StringRef class_name) {
+ if (class_name.empty())
+ return llvm::createStringError("empty class name");
+
+ return ScriptedPythonInterface::CreatePluginObject(
+ ScriptedMetadata(class_name, nullptr), nullptr);
+}
+
+llvm::Expected<std::string> ScriptedStringSummaryPythonInterface::GetSummary(
+ ValueObject &valobj, const TypeSummaryOptions &options) {
+ Status error;
+ StructuredData::ObjectSP obj =
+ Dispatch("get_summary", error, valobj.GetSP(), options);
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return error.ToError();
+ return obj->GetStringValue().str();
+}
+
+void ScriptedStringSummaryPythonInterface::Initialize() {
+ const std::vector<llvm::StringRef> ci_usages = {
+ "type summary add -L <ClassName> [-K <key> -V <value> ...] <TypeName>"};
+ const std::vector<llvm::StringRef> api_usages = {
+ "SBTypeSummary.CreateWithClassName"};
+ PluginManager::RegisterPlugin(
+ GetPluginNameStatic(),
+ "Provide a summary string for a type, used by 'type summary add -l'",
+ CreateInstance, eScriptedExtensionScriptedStringSummary,
+ eScriptLanguagePython, {ci_usages, api_usages});
+}
+
+void ScriptedStringSummaryPythonInterface::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStringSummaryPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStringSummaryPythonInterface.h
new file mode 100644
index 0000000000000..0968ff8c9c403
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStringSummaryPythonInterface.h
@@ -0,0 +1,48 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_SOURCE_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDSTRINGSUMMARYPYTHONINTERFACE_H
+#define LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDSTRINGSUMMARYPYTHONINTERFACE_H
+
+#include "lldb/Interpreter/Interfaces/ScriptedStringSummaryInterface.h"
+
+#include "ScriptedPythonInterface.h"
+namespace lldb_private {
+
+class ScriptedStringSummaryPythonInterface
+ : public ScriptedStringSummaryInterface,
+ public ScriptedPythonInterface,
+ public PluginInterface {
+public:
+ ScriptedStringSummaryPythonInterface(
+ ScriptInterpreterPythonImpl &interpreter);
+
+ llvm::Expected<StructuredData::GenericSP>
+ CreatePluginObject(llvm::StringRef class_name) override;
+
+ llvm::SmallVector<AbstractMethodRequirement>
+ GetAbstractMethodRequirements() const override {
+ return llvm::SmallVector<AbstractMethodRequirement>({{"get_summary", 3}});
+ }
+
+ llvm::Expected<std::string>
+ GetSummary(ValueObject &valobj, const TypeSummaryOptions &options) override;
+
+ static void Initialize();
+
+ static void Terminate();
+
+ static llvm::StringRef GetPluginNameStatic() {
+ return "ScriptedStringSummaryPythonInterface";
+ }
+
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+};
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDSTRINGSUMMARYPYTHONINTERFACE_H
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
index 7b1bd9d8411c5..71d607814c238 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -289,6 +289,8 @@ llvm::Expected<std::string> ScriptInterpreterPython::ExtensionToImportPath(
return "lldb.plugins.scripted_process";
case eScriptedExtensionScriptedStackFrameRecognizer:
return "lldb.plugins.scripted_stackframe_recognizer";
+ case eScriptedExtensionScriptedStringSummary:
+ return "lldb.plugins.scripted_string_summary";
case eScriptedExtensionInvalid:
return llvm::createStringError("invalid extension name");
}
@@ -2003,6 +2005,11 @@ ScriptInterpreterPythonImpl::CreateScriptedStackFrameRecognizerInterface() {
return std::make_shared<ScriptedStackFrameRecognizerPythonInterface>(*this);
}
+ScriptedStringSummaryInterfaceSP
+ScriptInterpreterPythonImpl::CreateScriptedStringSummaryInterface() {
+ return std::make_shared<ScriptedStringSummaryPythonInterface>(*this);
+}
+
ScriptedThreadInterfaceSP
ScriptInterpreterPythonImpl::CreateScriptedThreadInterface() {
return std::make_shared<ScriptedThreadPythonInterface>(*this);
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
index d8a817198253f..570be07cc4e3b 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
@@ -86,6 +86,9 @@ class ScriptInterpreterPythonImpl : public ScriptInterpreterPython {
lldb::ScriptedStackFrameRecognizerInterfaceSP
CreateScriptedStackFrameRecognizerInterface() override;
+ lldb::ScriptedStringSummaryInterfaceSP
+ CreateScriptedStringSummaryInterface() override;
+
lldb::ScriptedThreadInterfaceSP CreateScriptedThreadInterface() override;
lldb::ScriptedFrameInterfaceSP CreateScriptedFrameInterface() override;
More information about the lldb-commits
mailing list