[Lldb-commits] [lldb] a07b91d - [lldb/script] Migrate frame recognizers onto ScriptedPythonInterface (#209805)
via lldb-commits
lldb-commits at lists.llvm.org
Thu Jul 16 18:00:30 PDT 2026
Author: Med Ismail Bennani
Date: 2026-07-16T18:00:26-07:00
New Revision: a07b91d8243b8a8051dbbe5739eacc7942269c61
URL: https://github.com/llvm/llvm-project/commit/a07b91d8243b8a8051dbbe5739eacc7942269c61
DIFF: https://github.com/llvm/llvm-project/commit/a07b91d8243b8a8051dbbe5739eacc7942269c61.diff
LOG: [lldb/script] Migrate frame recognizers onto ScriptedPythonInterface (#209805)
Give `frame recognizer add -l` a formal
ScriptedStackFrameRecognizerInterface, matching the architecture already
used by ScriptedProcess, ScriptedBreakpoint, etc.: a C++ interface
header, a Python-backed implementation built on
ScriptedPythonInterface's CreatePluginObject/Dispatch machinery,
PluginManager registration, and a generatable Python ABC template
(scripted_stackframe_recognizer.py).
get_recognized_arguments' documented contract returns a plain list of
lldb.SBValue (not an lldb.SBValueList), so it bypasses the generic
Dispatch<ValueObjectListSP>() extractor and calls the SWIG bridge
directly, matching the legacy behavior exactly.
ScriptedStackFrameRecognizer now holds a single interface object created
once in its constructor and reused across every RecognizeFrame() call,
same lifecycle as before.
Signed-off-by: Med Ismail Bennani <ismail at bennani.ma>
Added:
lldb/examples/python/templates/scripted_stackframe_recognizer.py
lldb/include/lldb/Interpreter/Interfaces/ScriptedStackFrameRecognizerInterface.h
lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStackFrameRecognizerPythonInterface.cpp
lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStackFrameRecognizerPythonInterface.h
Modified:
lldb/bindings/python/CMakeLists.txt
lldb/bindings/python/python-wrapper.swig
lldb/docs/CMakeLists.txt
lldb/include/lldb/Interpreter/ScriptInterpreter.h
lldb/include/lldb/Target/StackFrameRecognizer.h
lldb/include/lldb/lldb-enumerations.h
lldb/include/lldb/lldb-forward.h
lldb/source/Interpreter/ScriptInterpreter.cpp
lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp
lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h
lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
lldb/source/Target/StackFrameRecognizer.cpp
lldb/test/API/commands/frame/recognizer/TestFrameRecognizer.py
lldb/test/API/commands/frame/recognizer/recognizer.py
lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
Removed:
################################################################################
diff --git a/lldb/bindings/python/CMakeLists.txt b/lldb/bindings/python/CMakeLists.txt
index 9a8a8d420e18a..d29b143c1408c 100644
--- a/lldb/bindings/python/CMakeLists.txt
+++ b/lldb/bindings/python/CMakeLists.txt
@@ -119,6 +119,7 @@ function(finish_swig_python swig_target lldb_python_bindings_dir lldb_python_tar
"${LLDB_SOURCE_DIR}/examples/python/templates/scripted_thread_plan.py"
"${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"
)
if(APPLE)
diff --git a/lldb/bindings/python/python-wrapper.swig b/lldb/bindings/python/python-wrapper.swig
index dea4f6b4c7f7c..2392737402e20 100644
--- a/lldb/bindings/python/python-wrapper.swig
+++ b/lldb/bindings/python/python-wrapper.swig
@@ -798,53 +798,6 @@ PythonObject lldb_private::python::SWIGBridge::LLDBSWIGPythonCreateOSPlugin(
return pfunc(SWIGBridge::ToSWIGWrapper(process_sp));
}
-PythonObject lldb_private::python::SWIGBridge::LLDBSWIGPython_CreateFrameRecognizer(
- const char *python_class_name, const char *session_dictionary_name) {
- if (python_class_name == NULL || python_class_name[0] == '\0' ||
- !session_dictionary_name)
- return PythonObject();
-
- PyErr_Cleaner py_err_cleaner(true);
-
- auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>(
- session_dictionary_name);
- auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(
- python_class_name, dict);
-
- if (!pfunc.IsAllocated())
- return PythonObject();
-
- return pfunc();
-}
-
-PyObject *lldb_private::python::SWIGBridge::LLDBSwigPython_GetRecognizedArguments(
- PyObject *implementor, const lldb::StackFrameSP &frame_sp) {
- static char callee_name[] = "get_recognized_arguments";
-
- PythonObject arg = SWIGBridge::ToSWIGWrapper(frame_sp);
-
- PythonString str(callee_name);
- PyObject *result =
- PyObject_CallMethodObjArgs(implementor, str.get(), arg.get(), NULL);
- return result;
-}
-
-bool lldb_private::python::SWIGBridge::LLDBSwigPython_ShouldHide(
- PyObject *implementor, const lldb::StackFrameSP &frame_sp) {
- static char callee_name[] = "should_hide";
-
- PythonObject arg = SWIGBridge::ToSWIGWrapper(frame_sp);
-
- PythonString str(callee_name);
-
- PyObject *result =
- PyObject_CallMethodObjArgs(implementor, str.get(), arg.get(), NULL);
- bool ret_val = result ? PyObject_IsTrue(result) : false;
- Py_XDECREF(result);
-
- return ret_val;
-}
-
void *lldb_private::python::SWIGBridge::LLDBSWIGPython_GetDynamicSetting(
void *module, const char *setting, const lldb::TargetSP &target_sp) {
if (!module || !setting)
diff --git a/lldb/docs/CMakeLists.txt b/lldb/docs/CMakeLists.txt
index 58c740f16bf78..dd091836dc1aa 100644
--- a/lldb/docs/CMakeLists.txt
+++ b/lldb/docs/CMakeLists.txt
@@ -32,6 +32,7 @@ if (LLDB_ENABLE_PYTHON AND SPHINX_FOUND)
COMMAND "${CMAKE_COMMAND}" -E copy "${LLDB_SOURCE_DIR}/examples/python/templates/scripted_thread_plan.py" "${CMAKE_CURRENT_BINARY_DIR}/lldb/plugins/"
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/"
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_stackframe_recognizer.py b/lldb/examples/python/templates/scripted_stackframe_recognizer.py
new file mode 100644
index 0000000000000..0c8489f8d6d2d
--- /dev/null
+++ b/lldb/examples/python/templates/scripted_stackframe_recognizer.py
@@ -0,0 +1,102 @@
+from abc import ABCMeta
+from typing import Optional
+
+import lldb
+
+
+class ScriptedStackFrameRecognizer(metaclass=ABCMeta):
+ """
+ The base class for a scripted stack frame recognizer.
+
+ A frame recognizer inspects a stack frame at stop time and can:
+
+ - attach recognized arguments to it (surfaced the same way as args
+ for unrecognized frames);
+ - hide the frame from backtraces;
+ - override the stop description reported for it;
+ - expose an exception object associated with it (e.g. a runtime's
+ thrown value);
+ - redirect auto-selection to a more relevant frame (e.g. bounce past
+ a language-runtime trampoline).
+
+ Register the recognizer with `frame recognizer add -l <ClassName> ...`.
+
+ Every method is optional: a recognizer only implements the ones it
+ cares about. A recognizer that just hides frames can implement only
+ `should_hide`; one that surfaces exception info can implement only
+ `get_exception` and `get_stop_description`.
+ """
+
+ def __init__(self):
+ """Construct a scripted stack frame recognizer.
+
+ Recognizers are constructed with no arguments and are shared across
+ every frame they're asked to recognize.
+ """
+ pass
+
+ def get_recognized_arguments(self, frame: lldb.SBFrame) -> list:
+ """Get the arguments recognized for this frame.
+
+ Args:
+ frame (lldb.SBFrame): The frame to inspect.
+
+ Returns:
+ list of lldb.SBValue: The recognized arguments, or an empty list
+ if none could be recognized.
+ """
+ return []
+
+ def should_hide(self, frame: lldb.SBFrame) -> bool:
+ """Whether this frame should be hidden when displaying backtraces.
+
+ Args:
+ frame (lldb.SBFrame): The frame to inspect.
+
+ Returns:
+ bool: `True` if this frame should be hidden, `False` otherwise.
+ Defaults to `False`.
+ """
+ return False
+
+ def select_most_relevant_frame(self, frame: lldb.SBFrame) -> Optional[lldb.SBFrame]:
+ """Pick a
diff erent frame to auto-select when the process stops in
+ this recognized frame. Useful when the recognized frame is trampoline
+ code that the user probably didn't want to land in (e.g. a language
+ runtime's exception-throw path).
+
+ Args:
+ frame (lldb.SBFrame): The recognized frame.
+
+ Returns:
+ lldb.SBFrame: The frame to select instead, or `None` to keep
+ the default selection.
+ """
+ return None
+
+ def get_exception(self, frame: lldb.SBFrame) -> Optional[lldb.SBValue]:
+ """Get the exception value associated with this recognized frame,
+ if any (e.g. the exception object at a language runtime's throw
+ site).
+
+ Args:
+ frame (lldb.SBFrame): The recognized frame.
+
+ Returns:
+ lldb.SBValue: The exception value, or `None` if this frame
+ doesn't correspond to an exception.
+ """
+ return None
+
+ def get_stop_description(self, frame: lldb.SBFrame) -> str:
+ """Get the stop description to surface for this recognized frame,
+ replacing whatever description lldb would have printed.
+
+ Args:
+ frame (lldb.SBFrame): The recognized frame.
+
+ Returns:
+ str: The stop description, or the empty string to keep the
+ default.
+ """
+ return ""
diff --git a/lldb/include/lldb/Interpreter/Interfaces/ScriptedStackFrameRecognizerInterface.h b/lldb/include/lldb/Interpreter/Interfaces/ScriptedStackFrameRecognizerInterface.h
new file mode 100644
index 0000000000000..333973b9f933b
--- /dev/null
+++ b/lldb/include/lldb/Interpreter/Interfaces/ScriptedStackFrameRecognizerInterface.h
@@ -0,0 +1,43 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_SCRIPTEDSTACKFRAMERECOGNIZERINTERFACE_H
+#define LLDB_INTERPRETER_INTERFACES_SCRIPTEDSTACKFRAMERECOGNIZERINTERFACE_H
+
+#include "ScriptedInterface.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+class ScriptedStackFrameRecognizerInterface : virtual public ScriptedInterface {
+public:
+ virtual llvm::Expected<StructuredData::GenericSP>
+ CreatePluginObject(const ScriptedMetadata &scripted_metadata) = 0;
+
+ virtual lldb::ValueObjectListSP
+ GetRecognizedArguments(lldb::StackFrameSP frame_sp) {
+ return lldb::ValueObjectListSP();
+ }
+
+ virtual bool ShouldHide(lldb::StackFrameSP frame_sp) { return false; }
+
+ virtual lldb::StackFrameSP
+ SelectMostRelevantFrame(lldb::StackFrameSP frame_sp) {
+ return nullptr;
+ }
+
+ virtual lldb::ValueObjectSP GetException(lldb::StackFrameSP frame_sp) {
+ return lldb::ValueObjectSP();
+ }
+
+ virtual std::string GetStopDescription(lldb::StackFrameSP frame_sp) {
+ return "";
+ }
+};
+} // namespace lldb_private
+
+#endif // LLDB_INTERPRETER_INTERFACES_SCRIPTEDSTACKFRAMERECOGNIZERINTERFACE_H
diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
index 2b9cb8f7bb866..122e779bf0279 100644
--- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h
+++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
@@ -248,22 +248,6 @@ class ScriptInterpreter : public PluginInterface {
return StructuredData::GenericSP();
}
- virtual StructuredData::GenericSP
- CreateFrameRecognizer(const char *class_name) {
- return StructuredData::GenericSP();
- }
-
- virtual lldb::ValueObjectListSP GetRecognizedArguments(
- const StructuredData::ObjectSP &implementor,
- lldb::StackFrameSP frame_sp) {
- return lldb::ValueObjectListSP();
- }
-
- virtual bool ShouldHide(const StructuredData::ObjectSP &implementor,
- lldb::StackFrameSP frame_sp) {
- return false;
- }
-
virtual StructuredData::ObjectSP
LoadPluginModule(const FileSpec &file_spec, lldb_private::Status &error) {
return StructuredData::ObjectSP();
@@ -572,6 +556,11 @@ class ScriptInterpreter : public PluginInterface {
return {};
}
+ virtual lldb::ScriptedStackFrameRecognizerInterfaceSP
+ CreateScriptedStackFrameRecognizerInterface() {
+ return {};
+ }
+
virtual StructuredData::ObjectSP
CreateStructuredDataFromScriptObject(ScriptObject obj) {
return {};
diff --git a/lldb/include/lldb/Target/StackFrameRecognizer.h b/lldb/include/lldb/Target/StackFrameRecognizer.h
index 97a35778ae070..95e8a03cac96c 100644
--- a/lldb/include/lldb/Target/StackFrameRecognizer.h
+++ b/lldb/include/lldb/Target/StackFrameRecognizer.h
@@ -77,8 +77,7 @@ class StackFrameRecognizer
/// tracks a particular Python classobject, which will be asked to recognize
/// stack frames.
class ScriptedStackFrameRecognizer : public StackFrameRecognizer {
- lldb_private::ScriptInterpreter *m_interpreter;
- lldb_private::StructuredData::ObjectSP m_python_object_sp;
+ lldb::ScriptedStackFrameRecognizerInterfaceSP m_interface_sp;
std::string m_python_class;
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index b36ad09f2e892..93c252b55de99 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -267,7 +267,8 @@ enum ScriptedExtension {
eScriptedExtensionScriptedHook,
eScriptedExtensionScriptedThread,
eScriptedExtensionScriptedFrame,
- kLastScriptedExtension = eScriptedExtensionScriptedFrame
+ eScriptedExtensionScriptedStackFrameRecognizer,
+ kLastScriptedExtension = eScriptedExtensionScriptedStackFrameRecognizer
};
/// Register numbering types.
diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h
index 6dbc095f15ef6..157aa5743f016 100644
--- a/lldb/include/lldb/lldb-forward.h
+++ b/lldb/include/lldb/lldb-forward.h
@@ -198,6 +198,7 @@ class ScriptedPlatformInterface;
class ScriptedProcessInterface;
class ScriptedThreadInterface;
class ScriptedThreadPlanInterface;
+class ScriptedStackFrameRecognizerInterface;
class ScriptedSyntheticChildren;
class SearchFilter;
class Section;
@@ -435,6 +436,8 @@ typedef std::shared_ptr<lldb_private::ScriptedThreadPlanInterface>
ScriptedThreadPlanInterfaceSP;
typedef std::shared_ptr<lldb_private::ScriptedBreakpointInterface>
ScriptedBreakpointInterfaceSP;
+typedef std::shared_ptr<lldb_private::ScriptedStackFrameRecognizerInterface>
+ ScriptedStackFrameRecognizerInterfaceSP;
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/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp
index 8420782b02814..6436d8161583d 100644
--- a/lldb/source/Interpreter/ScriptInterpreter.cpp
+++ b/lldb/source/Interpreter/ScriptInterpreter.cpp
@@ -212,6 +212,8 @@ ScriptInterpreter::ExtensionToString(lldb::ScriptedExtension extension) {
return "ScriptedThread";
case eScriptedExtensionScriptedFrame:
return "ScriptedFrame";
+ case eScriptedExtensionScriptedStackFrameRecognizer:
+ return "ScriptedStackFrameRecognizer";
}
llvm_unreachable("unhandled ScriptedExtension");
}
@@ -230,6 +232,8 @@ ScriptInterpreter::StringToExtension(llvm::StringRef string) {
.CaseLower("ScriptedHook", eScriptedExtensionScriptedHook)
.CaseLower("ScriptedThread", eScriptedExtensionScriptedThread)
.CaseLower("ScriptedFrame", eScriptedExtensionScriptedFrame)
+ .CaseLower("ScriptedStackFrameRecognizer",
+ eScriptedExtensionScriptedStackFrameRecognizer)
.Default(eScriptedExtensionInvalid);
}
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
index fb7d0cb82f8ca..201574da72a19 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
@@ -32,6 +32,7 @@ set(python_plugin_sources
Interfaces/ScriptedPythonInterface.cpp
Interfaces/ScriptedHookPythonInterface.cpp
Interfaces/ScriptedBreakpointPythonInterface.cpp
+ Interfaces/ScriptedStackFrameRecognizerPythonInterface.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 cdbb624706f83..8914f6b239023 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp
@@ -29,6 +29,7 @@ void ScriptInterpreterPythonInterfaces::Initialize() {
ScriptedFrameProviderPythonInterface::Initialize();
ScriptedThreadPythonInterface::Initialize();
ScriptedFramePythonInterface::Initialize();
+ ScriptedStackFrameRecognizerPythonInterface::Initialize();
}
void ScriptInterpreterPythonInterfaces::Terminate() {
@@ -41,4 +42,5 @@ void ScriptInterpreterPythonInterfaces::Terminate() {
ScriptedFrameProviderPythonInterface::Terminate();
ScriptedThreadPythonInterface::Terminate();
ScriptedFramePythonInterface::Terminate();
+ ScriptedStackFrameRecognizerPythonInterface::Terminate();
}
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h
index 9f6324d0503f7..03d747e63a592 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h
@@ -19,6 +19,7 @@
#include "ScriptedHookPythonInterface.h"
#include "ScriptedPlatformPythonInterface.h"
#include "ScriptedProcessPythonInterface.h"
+#include "ScriptedStackFrameRecognizerPythonInterface.h"
#include "ScriptedThreadPlanPythonInterface.h"
#include "ScriptedThreadPythonInterface.h"
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
index 4612b1939b5db..61ceb40dd9d32 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
@@ -305,22 +305,57 @@ template <>
lldb::ValueObjectListSP
ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::ValueObjectListSP>(
python::PythonObject &p, Status &error) {
- lldb::SBValueList *sb_value_list = reinterpret_cast<lldb::SBValueList *>(
- python::LLDBSWIGPython_CastPyObjectToSBValueList(p.get()));
-
- if (!sb_value_list) {
- error = Status::FromErrorStringWithFormat(
- "couldn't cast lldb::SBValueList to lldb::ValueObjectListSP");
- return {};
+ // Two Python return shapes are accepted here so callers can go through
+ // Dispatch<ValueObjectListSP>() uniformly: an `SBValueList` wrapper
+ // (what most extension methods return) and a plain Python `list` of
+ // `SBValue` (what `get_recognized_arguments` is documented to return).
+ lldb::ValueObjectListSP out = std::make_shared<ValueObjectList>();
+ if (auto *sb_value_list = reinterpret_cast<lldb::SBValueList *>(
+ python::LLDBSWIGPython_CastPyObjectToSBValueList(p.get()))) {
+ for (uint32_t i = 0, e = sb_value_list->GetSize(); i < e; ++i) {
+ SBValue value = sb_value_list->GetValueAtIndex(i);
+ out->Append(m_interpreter.GetOpaqueTypeFromSBValue(value));
+ }
+ return out;
}
- lldb::ValueObjectListSP out = std::make_shared<ValueObjectList>();
- for (uint32_t i = 0, e = sb_value_list->GetSize(); i < e; ++i) {
- SBValue value = sb_value_list->GetValueAtIndex(i);
- out->Append(m_interpreter.GetOpaqueTypeFromSBValue(value));
+ // Fallback: a plain Python `list` of `SBValue`. Round-trip through
+ // `CreateStructuredObject` so we don't touch the `PyList_*` C API
+ // directly; unknown-shape items surface as `StructuredData::Generic`
+ // holding their opaque `PyObject*`, which we hand back to SWIG to
+ // recover the SBValue wrapper.
+ StructuredData::ObjectSP structured = p.CreateStructuredObject();
+ StructuredData::Array *arr = structured ? structured->GetAsArray() : nullptr;
+ if (arr) {
+ size_t index = 0;
+ bool aborted = false;
+ arr->ForEach([&](StructuredData::Object *item) {
+ StructuredData::Generic *generic = item ? item->GetAsGeneric() : nullptr;
+ if (!generic) {
+ error = Status::FromErrorStringWithFormatv(
+ "ValueObjectList item at index {0} is not a "
+ "StructuredData::Generic",
+ index);
+ aborted = true;
+ return false;
+ }
+ auto *sb_value = reinterpret_cast<lldb::SBValue *>(
+ python::LLDBSWIGPython_CastPyObjectToSBValue(
+ static_cast<PyObject *>(generic->GetValue())));
+ if (sb_value)
+ if (auto valobj_sp = m_interpreter.GetOpaqueTypeFromSBValue(*sb_value))
+ out->Append(valobj_sp);
+ ++index;
+ return true;
+ });
+ if (aborted)
+ return {};
+ return out;
}
- return out;
+ error = Status::FromErrorStringWithFormat(
+ "couldn't extract ValueObjectList from Python return value");
+ return {};
}
template <>
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStackFrameRecognizerPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStackFrameRecognizerPythonInterface.cpp
new file mode 100644
index 0000000000000..2e05928a2ad57
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStackFrameRecognizerPythonInterface.cpp
@@ -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
+//
+//===----------------------------------------------------------------------===//
+
+#include "../lldb-python.h"
+
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "../SWIGPythonBridge.h"
+#include "../ScriptInterpreterPythonImpl.h"
+#include "ScriptedStackFrameRecognizerPythonInterface.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::python;
+
+ScriptedStackFrameRecognizerPythonInterface::
+ ScriptedStackFrameRecognizerPythonInterface(
+ ScriptInterpreterPythonImpl &interpreter)
+ : ScriptedStackFrameRecognizerInterface(),
+ ScriptedPythonInterface(interpreter) {}
+
+llvm::Expected<StructuredData::GenericSP>
+ScriptedStackFrameRecognizerPythonInterface::CreatePluginObject(
+ const ScriptedMetadata &scripted_metadata) {
+ return ScriptedPythonInterface::CreatePluginObject(scripted_metadata,
+ nullptr);
+}
+
+lldb::ValueObjectListSP
+ScriptedStackFrameRecognizerPythonInterface::GetRecognizedArguments(
+ lldb::StackFrameSP frame_sp) {
+ Status error;
+ return Dispatch<lldb::ValueObjectListSP>("get_recognized_arguments", error,
+ frame_sp);
+}
+
+bool ScriptedStackFrameRecognizerPythonInterface::ShouldHide(
+ lldb::StackFrameSP frame_sp) {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("should_hide", error, frame_sp);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return false;
+
+ return obj->GetBooleanValue();
+}
+
+lldb::StackFrameSP
+ScriptedStackFrameRecognizerPythonInterface::SelectMostRelevantFrame(
+ lldb::StackFrameSP frame_sp) {
+ Status error;
+ return Dispatch<lldb::StackFrameSP>("select_most_relevant_frame", error,
+ frame_sp);
+}
+
+lldb::ValueObjectSP ScriptedStackFrameRecognizerPythonInterface::GetException(
+ lldb::StackFrameSP frame_sp) {
+ Status error;
+ return Dispatch<lldb::ValueObjectSP>("get_exception", error, frame_sp);
+}
+
+std::string ScriptedStackFrameRecognizerPythonInterface::GetStopDescription(
+ lldb::StackFrameSP frame_sp) {
+ Status error;
+ StructuredData::ObjectSP obj =
+ Dispatch("get_stop_description", error, frame_sp);
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return "";
+ return obj->GetStringValue().str();
+}
+
+void ScriptedStackFrameRecognizerPythonInterface::Initialize() {
+ const std::vector<llvm::StringRef> ci_usages = {
+ "frame recognizer add -l <script-name> [-s <shlib> ...] "
+ "[-n <symbol> ... | -x <symbol-regex>] [-f false] "
+ "[--mangled-name-preference <mode>]"};
+ PluginManager::RegisterPlugin(
+ GetPluginNameStatic(),
+ "Recognize a stack frame and provide extra information about it "
+ "(recognized arguments, exception object, stop description, "
+ "hidden/most-relevant frame).",
+ CreateInstance, eScriptedExtensionScriptedStackFrameRecognizer,
+ eScriptLanguagePython, {ci_usages, {}});
+}
+
+void ScriptedStackFrameRecognizerPythonInterface::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStackFrameRecognizerPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStackFrameRecognizerPythonInterface.h
new file mode 100644
index 0000000000000..eaf4116ab54c0
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStackFrameRecognizerPythonInterface.h
@@ -0,0 +1,57 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_SCRIPTEDSTACKFRAMERECOGNIZERPYTHONINTERFACE_H
+#define LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDSTACKFRAMERECOGNIZERPYTHONINTERFACE_H
+
+#include "lldb/Interpreter/Interfaces/ScriptedStackFrameRecognizerInterface.h"
+
+#include "ScriptedPythonInterface.h"
+namespace lldb_private {
+
+class ScriptedStackFrameRecognizerPythonInterface
+ : public ScriptedStackFrameRecognizerInterface,
+ public ScriptedPythonInterface,
+ public PluginInterface {
+public:
+ ScriptedStackFrameRecognizerPythonInterface(
+ ScriptInterpreterPythonImpl &interpreter);
+
+ llvm::Expected<StructuredData::GenericSP>
+ CreatePluginObject(const ScriptedMetadata &scripted_metadata) override;
+
+ llvm::SmallVector<AbstractMethodRequirement>
+ GetAbstractMethodRequirements() const override {
+ return {};
+ }
+
+ lldb::ValueObjectListSP
+ GetRecognizedArguments(lldb::StackFrameSP frame_sp) override;
+
+ bool ShouldHide(lldb::StackFrameSP frame_sp) override;
+
+ lldb::StackFrameSP
+ SelectMostRelevantFrame(lldb::StackFrameSP frame_sp) override;
+
+ lldb::ValueObjectSP GetException(lldb::StackFrameSP frame_sp) override;
+
+ std::string GetStopDescription(lldb::StackFrameSP frame_sp) override;
+
+ static void Initialize();
+
+ static void Terminate();
+
+ static llvm::StringRef GetPluginNameStatic() {
+ return "ScriptedStackFrameRecognizerPythonInterface";
+ }
+
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+};
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDSTACKFRAMERECOGNIZERPYTHONINTERFACE_H
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
index ce9e12dbf7d3d..07e0da1dcf70d 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
@@ -214,17 +214,6 @@ class SWIGBridge {
const char *session_dictionary_name,
const lldb::ProcessSP &process_sp);
- static python::PythonObject
- LLDBSWIGPython_CreateFrameRecognizer(const char *python_class_name,
- const char *session_dictionary_name);
-
- static PyObject *
- LLDBSwigPython_GetRecognizedArguments(PyObject *implementor,
- const lldb::StackFrameSP &frame_sp);
-
- static bool LLDBSwigPython_ShouldHide(PyObject *implementor,
- const lldb::StackFrameSP &frame_sp);
-
static bool LLDBSWIGPythonRunScriptKeywordProcess(
const char *python_function_name, const char *session_dictionary_name,
const lldb::ProcessSP &process, std::string &output);
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
index f3f2b801d43e2..a153563b4534b 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -1624,92 +1624,6 @@ bool ScriptInterpreterPythonImpl::GenerateTypeSynthClass(
return true;
}
-StructuredData::GenericSP
-ScriptInterpreterPythonImpl::CreateFrameRecognizer(const char *class_name) {
- if (class_name == nullptr || class_name[0] == '\0')
- return StructuredData::GenericSP();
-
- Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock);
- PythonObject ret_val = SWIGBridge::LLDBSWIGPython_CreateFrameRecognizer(
- class_name, m_dictionary_name.c_str());
-
- return StructuredData::GenericSP(
- new StructuredPythonObject(std::move(ret_val)));
-}
-
-lldb::ValueObjectListSP ScriptInterpreterPythonImpl::GetRecognizedArguments(
- const StructuredData::ObjectSP &os_plugin_object_sp,
- lldb::StackFrameSP frame_sp) {
- Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock);
-
- if (!os_plugin_object_sp)
- return ValueObjectListSP();
-
- StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric();
- if (!generic)
- return nullptr;
-
- PythonObject implementor(PyRefType::Borrowed,
- (PyObject *)generic->GetValue());
-
- if (!implementor.IsAllocated())
- return ValueObjectListSP();
-
- PythonObject py_return(PyRefType::Owned,
- SWIGBridge::LLDBSwigPython_GetRecognizedArguments(
- implementor.get(), frame_sp));
-
- // if it fails, print the error but otherwise go on
- if (PyErr_Occurred()) {
- PyErr_Print();
- PyErr_Clear();
- }
- if (py_return.get()) {
- PythonList result_list(PyRefType::Borrowed, py_return.get());
- ValueObjectListSP result = std::make_shared<ValueObjectList>();
- for (size_t i = 0; i < result_list.GetSize(); i++) {
- PyObject *item = result_list.GetItemAtIndex(i).get();
- lldb::SBValue *sb_value_ptr =
- (lldb::SBValue *)LLDBSWIGPython_CastPyObjectToSBValue(item);
- auto valobj_sp =
- SWIGBridge::LLDBSWIGPython_GetValueObjectSPFromSBValue(sb_value_ptr);
- if (valobj_sp)
- result->Append(valobj_sp);
- }
- return result;
- }
- return ValueObjectListSP();
-}
-
-bool ScriptInterpreterPythonImpl::ShouldHide(
- const StructuredData::ObjectSP &os_plugin_object_sp,
- lldb::StackFrameSP frame_sp) {
- Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock);
-
- if (!os_plugin_object_sp)
- return false;
-
- StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric();
- if (!generic)
- return false;
-
- PythonObject implementor(PyRefType::Borrowed,
- (PyObject *)generic->GetValue());
-
- if (!implementor.IsAllocated())
- return false;
-
- bool result =
- SWIGBridge::LLDBSwigPython_ShouldHide(implementor.get(), frame_sp);
-
- // if it fails, print the error but otherwise go on
- if (PyErr_Occurred()) {
- PyErr_Print();
- PyErr_Clear();
- }
- return result;
-}
-
ScriptedProcessInterfaceUP
ScriptInterpreterPythonImpl::CreateScriptedProcessInterface() {
return std::make_unique<ScriptedProcessPythonInterface>(*this);
@@ -1725,6 +1639,11 @@ ScriptInterpreterPythonImpl::CreateScriptedBreakpointInterface() {
return std::make_shared<ScriptedBreakpointPythonInterface>(*this);
}
+ScriptedStackFrameRecognizerInterfaceSP
+ScriptInterpreterPythonImpl::CreateScriptedStackFrameRecognizerInterface() {
+ return std::make_shared<ScriptedStackFrameRecognizerPythonInterface>(*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 353332a784e60..d8a817198253f 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
@@ -76,16 +76,6 @@ class ScriptInterpreterPythonImpl : public ScriptInterpreterPython {
StructuredData::ObjectSP
CreateStructuredDataFromScriptObject(ScriptObject obj) override;
- StructuredData::GenericSP
- CreateFrameRecognizer(const char *class_name) override;
-
- lldb::ValueObjectListSP
- GetRecognizedArguments(const StructuredData::ObjectSP &implementor,
- lldb::StackFrameSP frame_sp) override;
-
- bool ShouldHide(const StructuredData::ObjectSP &implementor,
- lldb::StackFrameSP frame_sp) override;
-
lldb::ScriptedProcessInterfaceUP CreateScriptedProcessInterface() override;
lldb::ScriptedHookInterfaceSP CreateScriptedHookInterface() override;
@@ -93,6 +83,9 @@ class ScriptInterpreterPythonImpl : public ScriptInterpreterPython {
lldb::ScriptedBreakpointInterfaceSP
CreateScriptedBreakpointInterface() override;
+ lldb::ScriptedStackFrameRecognizerInterfaceSP
+ CreateScriptedStackFrameRecognizerInterface() override;
+
lldb::ScriptedThreadInterfaceSP CreateScriptedThreadInterface() override;
lldb::ScriptedFrameInterfaceSP CreateScriptedFrameInterface() override;
diff --git a/lldb/source/Target/StackFrameRecognizer.cpp b/lldb/source/Target/StackFrameRecognizer.cpp
index f297c71ff44d7..589f3805e3a67 100644
--- a/lldb/source/Target/StackFrameRecognizer.cpp
+++ b/lldb/source/Target/StackFrameRecognizer.cpp
@@ -8,39 +8,62 @@
#include "lldb/Target/StackFrameRecognizer.h"
#include "lldb/Core/Module.h"
+#include "lldb/Interpreter/Interfaces/ScriptedStackFrameRecognizerInterface.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/ScriptedMetadata.h"
using namespace lldb;
using namespace lldb_private;
class ScriptedRecognizedStackFrame : public RecognizedStackFrame {
bool m_hidden;
+ lldb::StackFrameSP m_most_relevant_frame;
+ lldb::ValueObjectSP m_exception;
public:
- ScriptedRecognizedStackFrame(ValueObjectListSP args, bool hidden)
- : m_hidden(hidden) {
+ ScriptedRecognizedStackFrame(ValueObjectListSP args, bool hidden,
+ lldb::StackFrameSP most_relevant_frame,
+ lldb::ValueObjectSP exception,
+ std::string stop_desc)
+ : m_hidden(hidden), m_most_relevant_frame(std::move(most_relevant_frame)),
+ m_exception(std::move(exception)) {
m_arguments = std::move(args);
+ m_stop_desc = std::move(stop_desc);
}
bool ShouldHide() override { return m_hidden; }
+ lldb::StackFrameSP GetMostRelevantFrame() override {
+ return m_most_relevant_frame;
+ }
+ lldb::ValueObjectSP GetExceptionObject() override { return m_exception; }
};
ScriptedStackFrameRecognizer::ScriptedStackFrameRecognizer(
ScriptInterpreter *interpreter, const char *pclass)
- : m_interpreter(interpreter), m_python_class(pclass) {
- m_python_object_sp =
- m_interpreter->CreateFrameRecognizer(m_python_class.c_str());
+ : m_python_class(pclass) {
+ if (!interpreter)
+ return;
+
+ m_interface_sp = interpreter->CreateScriptedStackFrameRecognizerInterface();
+ if (!m_interface_sp)
+ return;
+
+ ScriptedMetadata scripted_metadata(m_python_class, nullptr);
+ auto obj_or_err = m_interface_sp->CreatePluginObject(scripted_metadata);
+ if (!obj_or_err) {
+ llvm::consumeError(obj_or_err.takeError());
+ m_interface_sp.reset();
+ }
}
RecognizedStackFrameSP
ScriptedStackFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame) {
- if (!m_python_object_sp || !m_interpreter)
+ if (!m_interface_sp)
return RecognizedStackFrameSP();
- ValueObjectListSP args =
- m_interpreter->GetRecognizedArguments(m_python_object_sp, frame);
+ ValueObjectListSP args = m_interface_sp->GetRecognizedArguments(frame);
auto args_synthesized = std::make_shared<ValueObjectList>();
if (args) {
for (const auto &o : args->GetObjects())
@@ -48,10 +71,15 @@ ScriptedStackFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame) {
*o, eValueTypeVariableArgument));
}
- bool hidden = m_interpreter->ShouldHide(m_python_object_sp, frame);
+ bool hidden = m_interface_sp->ShouldHide(frame);
+ lldb::StackFrameSP most_relevant =
+ m_interface_sp->SelectMostRelevantFrame(frame);
+ lldb::ValueObjectSP exception = m_interface_sp->GetException(frame);
+ std::string stop_desc = m_interface_sp->GetStopDescription(frame);
- return RecognizedStackFrameSP(
- new ScriptedRecognizedStackFrame(args_synthesized, hidden));
+ return RecognizedStackFrameSP(new ScriptedRecognizedStackFrame(
+ args_synthesized, hidden, std::move(most_relevant), std::move(exception),
+ std::move(stop_desc)));
}
void StackFrameRecognizerManager::BumpGeneration() {
diff --git a/lldb/test/API/commands/frame/recognizer/TestFrameRecognizer.py b/lldb/test/API/commands/frame/recognizer/TestFrameRecognizer.py
index 68df086143585..9e3142a691c72 100644
--- a/lldb/test/API/commands/frame/recognizer/TestFrameRecognizer.py
+++ b/lldb/test/API/commands/frame/recognizer/TestFrameRecognizer.py
@@ -222,6 +222,46 @@ def test_frame_recognizer_hiding(self):
frame = thread.GetSelectedFrame()
self.assertIn("main", frame.name)
+ def test_frame_recognizer_optional_hooks(self):
+ """Exercise select_most_relevant_frame, get_exception, and
+ get_stop_description via a recognizer that implements all three.
+ Each hook records the frame name it saw in a class-level list so
+ the test can assert the hook actually fired."""
+ self.build()
+
+ target, process, thread, _ = lldbutil.run_to_name_breakpoint(self, "nested")
+
+ self.expect("frame recognizer clear")
+ self.expect(
+ "command script import "
+ + os.path.join(self.getSourceDir(), "recognizer.py")
+ )
+
+ # Reset the call trackers to isolate this test's activity from
+ # anything the recognizer might have observed earlier.
+ import recognizer
+
+ recognizer.NestedFrameRecognizer.select_most_relevant_frame_calls.clear()
+ recognizer.NestedFrameRecognizer.get_exception_calls.clear()
+ recognizer.NestedFrameRecognizer.get_stop_description_calls.clear()
+
+ self.expect(
+ "frame recognizer add -l recognizer.NestedFrameRecognizer "
+ "-f false -s a.out -n nested"
+ )
+
+ # Backtracing triggers recognition on each frame lldb walks.
+ self.runCmd("thread backtrace")
+
+ self.assertIn(
+ "nested", recognizer.NestedFrameRecognizer.select_most_relevant_frame_calls
+ )
+ self.assertIn("nested", recognizer.NestedFrameRecognizer.get_exception_calls)
+ self.assertIn(
+ "nested",
+ recognizer.NestedFrameRecognizer.get_stop_description_calls,
+ )
+
def test_frame_recognizer_multi_symbol(self):
self.build()
exe = self.getBuildArtifact("a.out")
diff --git a/lldb/test/API/commands/frame/recognizer/recognizer.py b/lldb/test/API/commands/frame/recognizer/recognizer.py
index 98666b720b1e2..e7ab03e18bbc4 100644
--- a/lldb/test/API/commands/frame/recognizer/recognizer.py
+++ b/lldb/test/API/commands/frame/recognizer/recognizer.py
@@ -3,7 +3,7 @@
import lldb
-class MyFrameRecognizer(object):
+class MyFrameRecognizer:
def get_recognized_arguments(self, frame):
if frame.name == "foo":
arg1 = frame.EvaluateExpression("$arg1").signed
@@ -33,11 +33,38 @@ def get_recognized_arguments(self, frame):
return []
-class MyOtherFrameRecognizer(object):
+class MyOtherFrameRecognizer:
def get_recognized_arguments(self, frame):
return []
-class BazFrameRecognizer(object):
+class BazFrameRecognizer:
def should_hide(self, frame):
return "baz" in frame.name
+
+
+class NestedFrameRecognizer:
+ """Exercises the optional hooks beyond `should_hide`: replace the
+ stop description, redirect the selected frame, and expose a synthetic
+ exception object. Tracks invocation via class-level lists so a test
+ can assert each hook actually fires.
+ """
+
+ select_most_relevant_frame_calls = []
+ get_exception_calls = []
+ get_stop_description_calls = []
+
+ def select_most_relevant_frame(self, frame):
+ self.select_most_relevant_frame_calls.append(frame.name)
+ # Redirect from `nested` (frame 0) to its caller `baz` (frame 1).
+ return frame.thread.frames[1] if frame.thread.num_frames > 1 else None
+
+ def get_exception(self, frame):
+ self.get_exception_calls.append(frame.name)
+ return frame.thread.process.target.CreateValueFromExpression(
+ "recognized_exception", "42"
+ )
+
+ def get_stop_description(self, frame):
+ self.get_stop_description_calls.append(frame.name)
+ return "recognized nested()"
diff --git a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
index 1ed6bee384a84..c9298191ec3c1 100644
--- a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
+++ b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
@@ -260,18 +260,6 @@ lldb_private::python::SWIGBridge::LLDBSWIGPythonCreateOSPlugin(
return python::PythonObject();
}
-python::PythonObject
-lldb_private::python::SWIGBridge::LLDBSWIGPython_CreateFrameRecognizer(
- const char *python_class_name, const char *session_dictionary_name) {
- return python::PythonObject();
-}
-
-PyObject *
-lldb_private::python::SWIGBridge::LLDBSwigPython_GetRecognizedArguments(
- PyObject *implementor, const lldb::StackFrameSP &frame_sp) {
- return nullptr;
-}
-
bool lldb_private::python::SWIGBridge::LLDBSWIGPythonRunScriptKeywordProcess(
const char *python_function_name, const char *session_dictionary_name,
const lldb::ProcessSP &process, std::string &output) {
More information about the lldb-commits
mailing list