Skip to content

Commit 1e131dd

Browse files
authored
[lldb/Interpreter] Introduce ScriptedStopHook{,Python}Interface & make use of it (#105449)
This patch introduces new `ScriptedStopHook{,Python}Interface` classes that make use of the Scripted Interface infrastructure and makes use of it in `StopHookScripted`. It also relax the requirement on the number of argument for initializing scripting extension if the size of the interface parameter pack contains 1 less element than the extension maximum number of positional arguments for this initializer. This addresses the cases where the embedded interpreter session dictionary is passed to the extension initializer which is not used most of the time. --------- Signed-off-by: Med Ismail Bennani <[email protected]>
1 parent f9bd083 commit 1e131dd

21 files changed

+299
-222
lines changed

lldb/bindings/python/python-wrapper.swig

Lines changed: 13 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -301,104 +301,6 @@ unsigned int lldb_private::python::SWIGBridge::LLDBSwigPythonCallBreakpointResol
301301
return ret_val;
302302
}
303303

304-
PythonObject lldb_private::python::SWIGBridge::LLDBSwigPythonCreateScriptedStopHook(
305-
lldb::TargetSP target_sp, const char *python_class_name,
306-
const char *session_dictionary_name, const StructuredDataImpl &args_impl,
307-
Status &error) {
308-
if (python_class_name == NULL || python_class_name[0] == '\0') {
309-
error = Status::FromErrorString("Empty class name.");
310-
return PythonObject();
311-
}
312-
if (!session_dictionary_name) {
313-
error = Status::FromErrorString("No session dictionary");
314-
return PythonObject();
315-
}
316-
317-
PyErr_Cleaner py_err_cleaner(true);
318-
319-
auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>(
320-
session_dictionary_name);
321-
auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(
322-
python_class_name, dict);
323-
324-
if (!pfunc.IsAllocated()) {
325-
error = Status::FromErrorStringWithFormat("Could not find class: %s.",
326-
python_class_name);
327-
return PythonObject();
328-
}
329-
330-
PythonObject result =
331-
pfunc(SWIGBridge::ToSWIGWrapper(target_sp), SWIGBridge::ToSWIGWrapper(args_impl), dict);
332-
333-
if (result.IsAllocated()) {
334-
// Check that the handle_stop callback is defined:
335-
auto callback_func = result.ResolveName<PythonCallable>("handle_stop");
336-
if (callback_func.IsAllocated()) {
337-
if (auto args_info = callback_func.GetArgInfo()) {
338-
size_t num_args = (*args_info).max_positional_args;
339-
if (num_args != 2) {
340-
error = Status::FromErrorStringWithFormat(
341-
"Wrong number of args for "
342-
"handle_stop callback, should be 2 (excluding self), got: %zu",
343-
num_args);
344-
return PythonObject();
345-
} else
346-
return result;
347-
} else {
348-
error = Status::FromErrorString(
349-
"Couldn't get num arguments for handle_stop "
350-
"callback.");
351-
return PythonObject();
352-
}
353-
return result;
354-
} else {
355-
error = Status::FromErrorStringWithFormat(
356-
"Class \"%s\" is missing the required "
357-
"handle_stop callback.",
358-
python_class_name);
359-
}
360-
}
361-
return PythonObject();
362-
}
363-
364-
bool lldb_private::python::SWIGBridge::LLDBSwigPythonStopHookCallHandleStop(
365-
void *implementor, lldb::ExecutionContextRefSP exc_ctx_sp,
366-
lldb::StreamSP stream) {
367-
// handle_stop will return a bool with the meaning "should_stop"...
368-
// If you return nothing we'll assume we are going to stop.
369-
// Also any errors should return true, since we should stop on error.
370-
371-
PyErr_Cleaner py_err_cleaner(false);
372-
PythonObject self(PyRefType::Borrowed, static_cast<PyObject *>(implementor));
373-
auto pfunc = self.ResolveName<PythonCallable>("handle_stop");
374-
375-
if (!pfunc.IsAllocated())
376-
return true;
377-
378-
std::shared_ptr<lldb::SBStream> sb_stream = std::make_shared<lldb::SBStream>();
379-
PythonObject sb_stream_arg = SWIGBridge::ToSWIGWrapper(sb_stream);
380-
PythonObject result =
381-
pfunc(SWIGBridge::ToSWIGWrapper(std::move(exc_ctx_sp)), sb_stream_arg);
382-
383-
if (PyErr_Occurred()) {
384-
stream->PutCString("Python error occurred handling stop-hook.");
385-
PyErr_Print();
386-
PyErr_Clear();
387-
return true;
388-
}
389-
390-
// Now add the result to the output stream. SBStream only
391-
// makes an internally help StreamString which I can't interpose, so I
392-
// have to copy it over here.
393-
stream->PutCString(sb_stream->GetData());
394-
sb_stream_arg.release();
395-
396-
if (result.get() == Py_False)
397-
return false;
398-
else
399-
return true;
400-
}
401-
402304
// wrapper that calls an optional instance member of an object taking no
403305
// arguments
404306
static PyObject *LLDBSwigPython_CallOptionalMember(
@@ -677,6 +579,19 @@ void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBMemoryRegionInfo(PyOb
677579
return sb_ptr;
678580
}
679581

582+
void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBExecutionContext(PyObject *
583+
data) {
584+
lldb::SBExecutionContext *sb_ptr = NULL;
585+
586+
int valid_cast = SWIG_ConvertPtr(data, (void **)&sb_ptr,
587+
SWIGTYPE_p_lldb__SBExecutionContext, 0);
588+
589+
if (valid_cast == -1)
590+
return NULL;
591+
592+
return sb_ptr;
593+
}
594+
680595
bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallCommand(
681596
const char *python_function_name, const char *session_dictionary_name,
682597
lldb::DebuggerSP debugger, const char *args,

lldb/include/lldb/API/SBExecutionContext.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <vector>
1717

1818
namespace lldb_private {
19+
class ScriptInterpreter;
1920
namespace python {
2021
class SWIGBridge;
2122
}
@@ -55,6 +56,7 @@ class LLDB_API SBExecutionContext {
5556

5657
protected:
5758
friend class lldb_private::python::SWIGBridge;
59+
friend class lldb_private::ScriptInterpreter;
5860

5961
lldb_private::ExecutionContextRef *get() const;
6062

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//===-- ScriptedStopHookInterface.h -----------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLDB_INTERPRETER_INTERFACES_SCRIPTEDSTOPHOOKINTERFACE_H
10+
#define LLDB_INTERPRETER_INTERFACES_SCRIPTEDSTOPHOOKINTERFACE_H
11+
12+
#include "lldb/lldb-private.h"
13+
14+
#include "ScriptedInterface.h"
15+
16+
namespace lldb_private {
17+
class ScriptedStopHookInterface : public ScriptedInterface {
18+
public:
19+
virtual llvm::Expected<StructuredData::GenericSP>
20+
CreatePluginObject(llvm::StringRef class_name, lldb::TargetSP target_sp,
21+
const StructuredDataImpl &args_sp) = 0;
22+
23+
/// "handle_stop" will return a bool with the meaning "should_stop"...
24+
/// If nothing is returned, we'll assume we are going to stop.
25+
/// Also any errors should return true, since we should stop on error.
26+
virtual llvm::Expected<bool> HandleStop(ExecutionContext &exe_ctx,
27+
lldb::StreamSP output_sp) {
28+
return true;
29+
}
30+
};
31+
} // namespace lldb_private
32+
33+
#endif // LLDB_INTERPRETER_INTERFACES_SCRIPTEDSTOPHOOKINTERFACE_H

lldb/include/lldb/Interpreter/ScriptInterpreter.h

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "lldb/API/SBData.h"
1515
#include "lldb/API/SBError.h"
1616
#include "lldb/API/SBEvent.h"
17+
#include "lldb/API/SBExecutionContext.h"
1718
#include "lldb/API/SBLaunchInfo.h"
1819
#include "lldb/API/SBMemoryRegionInfo.h"
1920
#include "lldb/API/SBStream.h"
@@ -271,24 +272,6 @@ class ScriptInterpreter : public PluginInterface {
271272
return lldb::eSearchDepthModule;
272273
}
273274

274-
virtual StructuredData::GenericSP
275-
CreateScriptedStopHook(lldb::TargetSP target_sp, const char *class_name,
276-
const StructuredDataImpl &args_data, Status &error) {
277-
error =
278-
Status::FromErrorString("Creating scripted stop-hooks with the current "
279-
"script interpreter is not supported.");
280-
return StructuredData::GenericSP();
281-
}
282-
283-
// This dispatches to the handle_stop method of the stop-hook class. It
284-
// returns a "should_stop" bool.
285-
virtual bool
286-
ScriptedStopHookHandleStop(StructuredData::GenericSP implementor_sp,
287-
ExecutionContext &exc_ctx,
288-
lldb::StreamSP stream_sp) {
289-
return true;
290-
}
291-
292275
virtual StructuredData::ObjectSP
293276
LoadPluginModule(const FileSpec &file_spec, lldb_private::Status &error) {
294277
return StructuredData::ObjectSP();
@@ -561,6 +544,10 @@ class ScriptInterpreter : public PluginInterface {
561544
return {};
562545
}
563546

547+
virtual lldb::ScriptedStopHookInterfaceSP CreateScriptedStopHookInterface() {
548+
return {};
549+
}
550+
564551
virtual StructuredData::ObjectSP
565552
CreateStructuredDataFromScriptObject(ScriptObject obj) {
566553
return {};
@@ -587,6 +574,9 @@ class ScriptInterpreter : public PluginInterface {
587574
std::optional<MemoryRegionInfo> GetOpaqueTypeFromSBMemoryRegionInfo(
588575
const lldb::SBMemoryRegionInfo &mem_region) const;
589576

577+
lldb::ExecutionContextRefSP GetOpaqueTypeFromSBExecutionContext(
578+
const lldb::SBExecutionContext &exe_ctx) const;
579+
590580
protected:
591581
Debugger &m_debugger;
592582
lldb::ScriptLanguage m_script_lang;

lldb/include/lldb/Target/Target.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1391,8 +1391,7 @@ class Target : public std::enable_shared_from_this<Target>,
13911391
/// This holds the dictionary of keys & values that can be used to
13921392
/// parametrize any given callback's behavior.
13931393
StructuredDataImpl m_extra_args;
1394-
/// This holds the python callback object.
1395-
StructuredData::GenericSP m_implementation_sp;
1394+
lldb::ScriptedStopHookInterfaceSP m_interface_sp;
13961395

13971396
/// Use CreateStopHook to make a new empty stop hook. The GetCommandPointer
13981397
/// and fill it with commands, and SetSpecifier to set the specifier shared

lldb/include/lldb/lldb-forward.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ class ScriptInterpreterLocker;
190190
class ScriptedMetadata;
191191
class ScriptedPlatformInterface;
192192
class ScriptedProcessInterface;
193+
class ScriptedStopHookInterface;
193194
class ScriptedThreadInterface;
194195
class ScriptedThreadPlanInterface;
195196
class ScriptedSyntheticChildren;
@@ -408,6 +409,8 @@ typedef std::unique_ptr<lldb_private::ScriptedPlatformInterface>
408409
ScriptedPlatformInterfaceUP;
409410
typedef std::unique_ptr<lldb_private::ScriptedProcessInterface>
410411
ScriptedProcessInterfaceUP;
412+
typedef std::shared_ptr<lldb_private::ScriptedStopHookInterface>
413+
ScriptedStopHookInterfaceSP;
411414
typedef std::shared_ptr<lldb_private::ScriptedThreadInterface>
412415
ScriptedThreadInterfaceSP;
413416
typedef std::shared_ptr<lldb_private::ScriptedThreadPlanInterface>

lldb/source/Interpreter/ScriptInterpreter.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,12 @@ ScriptInterpreter::GetOpaqueTypeFromSBMemoryRegionInfo(
125125
return *mem_region.m_opaque_up.get();
126126
}
127127

128+
lldb::ExecutionContextRefSP
129+
ScriptInterpreter::GetOpaqueTypeFromSBExecutionContext(
130+
const lldb::SBExecutionContext &exe_ctx) const {
131+
return exe_ctx.m_exe_ctx_sp;
132+
}
133+
128134
lldb::ScriptLanguage
129135
ScriptInterpreter::StringToLanguage(const llvm::StringRef &language) {
130136
if (language.equals_insensitive(LanguageToString(eScriptLanguageNone)))

lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ add_lldb_library(lldbPluginScriptInterpreterPythonInterfaces PLUGIN
2525
ScriptedPlatformPythonInterface.cpp
2626
ScriptedProcessPythonInterface.cpp
2727
ScriptedPythonInterface.cpp
28+
ScriptedStopHookPythonInterface.cpp
2829
ScriptedThreadPlanPythonInterface.cpp
2930
ScriptedThreadPythonInterface.cpp
3031

lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,15 @@ void ScriptInterpreterPythonInterfaces::Initialize() {
2828
OperatingSystemPythonInterface::Initialize();
2929
ScriptedPlatformPythonInterface::Initialize();
3030
ScriptedProcessPythonInterface::Initialize();
31+
ScriptedStopHookPythonInterface::Initialize();
3132
ScriptedThreadPlanPythonInterface::Initialize();
3233
}
3334

3435
void ScriptInterpreterPythonInterfaces::Terminate() {
3536
OperatingSystemPythonInterface::Terminate();
3637
ScriptedPlatformPythonInterface::Terminate();
3738
ScriptedProcessPythonInterface::Terminate();
39+
ScriptedStopHookPythonInterface::Terminate();
3840
ScriptedThreadPlanPythonInterface::Terminate();
3941
}
4042

lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "OperatingSystemPythonInterface.h"
1919
#include "ScriptedPlatformPythonInterface.h"
2020
#include "ScriptedProcessPythonInterface.h"
21+
#include "ScriptedStopHookPythonInterface.h"
2122
#include "ScriptedThreadPlanPythonInterface.h"
2223

2324
namespace lldb_private {

lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,4 +159,23 @@ ScriptedPythonInterface::ExtractValueFromPythonObject<
159159
return m_interpreter.GetOpaqueTypeFromSBMemoryRegionInfo(*sb_mem_reg_info);
160160
}
161161

162+
template <>
163+
lldb::ExecutionContextRefSP
164+
ScriptedPythonInterface::ExtractValueFromPythonObject<
165+
lldb::ExecutionContextRefSP>(python::PythonObject &p, Status &error) {
166+
167+
lldb::SBExecutionContext *sb_exe_ctx =
168+
reinterpret_cast<lldb::SBExecutionContext *>(
169+
python::LLDBSWIGPython_CastPyObjectToSBExecutionContext(p.get()));
170+
171+
if (!sb_exe_ctx) {
172+
error = Status::FromErrorStringWithFormat(
173+
"Couldn't cast lldb::SBExecutionContext to "
174+
"lldb::ExecutionContextRefSP.");
175+
return {};
176+
}
177+
178+
return m_interpreter.GetOpaqueTypeFromSBExecutionContext(*sb_exe_ctx);
179+
}
180+
162181
#endif

lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -180,12 +180,35 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
180180
llvm::Expected<PythonObject> expected_return_object =
181181
create_error("Resulting object is not initialized.");
182182

183-
std::apply(
184-
[&init, &expected_return_object](auto &&...args) {
185-
llvm::consumeError(expected_return_object.takeError());
186-
expected_return_object = init(args...);
187-
},
188-
transformed_args);
183+
// This relax the requirement on the number of argument for
184+
// initializing scripting extension if the size of the interface
185+
// parameter pack contains 1 less element than the extension maximum
186+
// number of positional arguments for this initializer.
187+
//
188+
// This addresses the cases where the embedded interpreter session
189+
// dictionary is passed to the extension initializer which is not used
190+
// most of the time.
191+
size_t num_args = sizeof...(Args);
192+
if (num_args != arg_info->max_positional_args) {
193+
if (num_args != arg_info->max_positional_args - 1)
194+
return create_error("Passed arguments ({0}) doesn't match the number "
195+
"of expected arguments ({1}).",
196+
num_args, arg_info->max_positional_args);
197+
198+
std::apply(
199+
[&init, &expected_return_object](auto &&...args) {
200+
llvm::consumeError(expected_return_object.takeError());
201+
expected_return_object = init(args...);
202+
},
203+
std::tuple_cat(transformed_args, std::make_tuple(dict)));
204+
} else {
205+
std::apply(
206+
[&init, &expected_return_object](auto &&...args) {
207+
llvm::consumeError(expected_return_object.takeError());
208+
expected_return_object = init(args...);
209+
},
210+
transformed_args);
211+
}
189212

190213
if (!expected_return_object)
191214
return expected_return_object.takeError();
@@ -405,6 +428,10 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
405428
return python::SWIGBridge::ToSWIGWrapper(arg);
406429
}
407430

431+
python::PythonObject Transform(lldb::TargetSP arg) {
432+
return python::SWIGBridge::ToSWIGWrapper(arg);
433+
}
434+
408435
python::PythonObject Transform(lldb::ProcessSP arg) {
409436
return python::SWIGBridge::ToSWIGWrapper(arg);
410437
}
@@ -557,6 +584,11 @@ std::optional<MemoryRegionInfo>
557584
ScriptedPythonInterface::ExtractValueFromPythonObject<
558585
std::optional<MemoryRegionInfo>>(python::PythonObject &p, Status &error);
559586

587+
template <>
588+
lldb::ExecutionContextRefSP
589+
ScriptedPythonInterface::ExtractValueFromPythonObject<
590+
lldb::ExecutionContextRefSP>(python::PythonObject &p, Status &error);
591+
560592
} // namespace lldb_private
561593

562594
#endif // LLDB_ENABLE_PYTHON

0 commit comments

Comments
 (0)