
Xcode uses a pseudoterminal for the debugger console. - The upside of this apporach is that it means that it can rely on LLDB's IOHandlers for multiline and script input. - The downside of this approach is that the command output is printed to the PTY and you don't get a SBCommandReturnObject. Adrian added support for inline diagnostics (#110901) and we'd like to access those from the IDE. This patch adds support for registering a callback in the command interpreter that gives access to the `(SB)CommandReturnObject` right before it will be printed. The callback implementation can choose whether it likes to handle printing the result or defer to lldb. If the callback indicated it handled the result, the command interpreter will skip printing the result. We considered a few other alternatives to solve this problem: - The most obvious one is using `HandleCommand`, which returns a `SBCommandReturnObject`. The problem with this approach is the multiline input mentioned above. We would need a way to tell the IDE that it should expect multiline input, which isn't known until LLDB starts handling the command. - To address the multiline issue,we considered exposing (some of the) IOHandler machinery through the SB API. To solve this particular issue, that would require reimplementing a ton of logic that already exists today in the CommandInterpeter. Furthermore that seems like overkill compared to the proposed solution. rdar://141254310
277 lines
12 KiB
C++
277 lines
12 KiB
C++
//===-- ScriptInterpreterPython.h -------------------------------*- C++ -*-===//
|
|
//
|
|
// 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_PLUGINS_SCRIPTINTERPRETER_PYTHON_SWIGPYTHONBRIDGE_H
|
|
#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SWIGPYTHONBRIDGE_H
|
|
|
|
#include <optional>
|
|
#include <string>
|
|
|
|
#include "lldb/Host/Config.h"
|
|
|
|
#if LLDB_ENABLE_PYTHON
|
|
|
|
// LLDB Python header must be included first
|
|
#include "lldb-python.h"
|
|
|
|
#include "Plugins/ScriptInterpreter/Python/PythonDataObjects.h"
|
|
#include "lldb/lldb-forward.h"
|
|
#include "lldb/lldb-types.h"
|
|
#include "llvm/Support/Error.h"
|
|
|
|
namespace lldb {
|
|
class SBEvent;
|
|
class SBCommandReturnObject;
|
|
class SBValue;
|
|
class SBStream;
|
|
class SBStructuredData;
|
|
class SBFileSpec;
|
|
class SBModuleSpec;
|
|
class SBStringList;
|
|
} // namespace lldb
|
|
|
|
namespace lldb_private {
|
|
namespace python {
|
|
|
|
typedef struct swig_type_info swig_type_info;
|
|
|
|
python::PythonObject ToSWIGHelper(void *obj, swig_type_info *info);
|
|
|
|
/// A class that automatically clears an SB object when it goes out of scope.
|
|
/// Use for cases where the SB object points to a temporary/unowned entity.
|
|
template <typename T> class ScopedPythonObject : PythonObject {
|
|
public:
|
|
ScopedPythonObject(T *sb, swig_type_info *info)
|
|
: PythonObject(ToSWIGHelper(sb, info)), m_sb(sb) {}
|
|
~ScopedPythonObject() {
|
|
if (m_sb)
|
|
*m_sb = T();
|
|
}
|
|
ScopedPythonObject(ScopedPythonObject &&rhs)
|
|
: PythonObject(std::move(rhs)), m_sb(std::exchange(rhs.m_sb, nullptr)) {}
|
|
ScopedPythonObject(const ScopedPythonObject &) = delete;
|
|
ScopedPythonObject &operator=(const ScopedPythonObject &) = delete;
|
|
ScopedPythonObject &operator=(ScopedPythonObject &&) = delete;
|
|
|
|
const PythonObject &obj() const { return *this; }
|
|
|
|
private:
|
|
T *m_sb;
|
|
};
|
|
|
|
// TODO: We may want to support other languages in the future w/ SWIG (we
|
|
// already support Lua right now, for example). We could create a generic
|
|
// SWIGBridge class and have this one specialize it, something like this:
|
|
//
|
|
// <typename T>
|
|
// class SWIGBridge {
|
|
// static T ToSWIGWrapper(...);
|
|
// };
|
|
//
|
|
// class SWIGPythonBridge : public SWIGBridge<PythonObject> {
|
|
// template<> static PythonObject ToSWIGWrapper(...);
|
|
// };
|
|
//
|
|
// And we should be able to more easily support things like Lua
|
|
class SWIGBridge {
|
|
public:
|
|
static PythonObject ToSWIGWrapper(std::unique_ptr<lldb::SBValue> value_sb);
|
|
static PythonObject
|
|
ToSWIGWrapper(std::unique_ptr<lldb::SBCommandReturnObject> result_up);
|
|
static PythonObject ToSWIGWrapper(lldb::ValueObjectSP value_sp);
|
|
static PythonObject ToSWIGWrapper(lldb::TargetSP target_sp);
|
|
static PythonObject ToSWIGWrapper(lldb::ProcessSP process_sp);
|
|
static PythonObject ToSWIGWrapper(lldb::ModuleSP module_sp);
|
|
static PythonObject ToSWIGWrapper(lldb::ThreadPlanSP thread_plan_sp);
|
|
static PythonObject ToSWIGWrapper(lldb::BreakpointSP breakpoint_sp);
|
|
static PythonObject ToSWIGWrapper(Status &&status);
|
|
static PythonObject ToSWIGWrapper(const StructuredDataImpl &data_impl);
|
|
static PythonObject ToSWIGWrapper(lldb::ThreadSP thread_sp);
|
|
static PythonObject ToSWIGWrapper(lldb::StackFrameSP frame_sp);
|
|
static PythonObject ToSWIGWrapper(lldb::DebuggerSP debugger_sp);
|
|
static PythonObject ToSWIGWrapper(lldb::WatchpointSP watchpoint_sp);
|
|
static PythonObject ToSWIGWrapper(lldb::BreakpointLocationSP bp_loc_sp);
|
|
static PythonObject ToSWIGWrapper(lldb::TypeImplSP type_impl_sp);
|
|
static PythonObject ToSWIGWrapper(lldb::ExecutionContextRefSP ctx_sp);
|
|
static PythonObject ToSWIGWrapper(const TypeSummaryOptions &summary_options);
|
|
static PythonObject ToSWIGWrapper(const SymbolContext &sym_ctx);
|
|
static PythonObject ToSWIGWrapper(const Stream *stream);
|
|
static PythonObject ToSWIGWrapper(std::shared_ptr<lldb::SBStream> stream_sb);
|
|
static PythonObject ToSWIGWrapper(Event *event);
|
|
|
|
static PythonObject ToSWIGWrapper(lldb::ProcessAttachInfoSP attach_info_sp);
|
|
static PythonObject ToSWIGWrapper(lldb::ProcessLaunchInfoSP launch_info_sp);
|
|
static PythonObject ToSWIGWrapper(lldb::DataExtractorSP data_extractor_sp);
|
|
|
|
static PythonObject
|
|
ToSWIGWrapper(std::unique_ptr<lldb::SBStructuredData> data_sb);
|
|
static PythonObject
|
|
ToSWIGWrapper(std::unique_ptr<lldb::SBFileSpec> file_spec_sb);
|
|
static PythonObject
|
|
ToSWIGWrapper(std::unique_ptr<lldb::SBModuleSpec> module_spec_sb);
|
|
|
|
static python::ScopedPythonObject<lldb::SBCommandReturnObject>
|
|
ToSWIGWrapper(CommandReturnObject &cmd_retobj);
|
|
// These prototypes are the Pythonic implementations of the required
|
|
// callbacks. Although these are scripting-language specific, their definition
|
|
// depends on the public API.
|
|
|
|
static llvm::Expected<bool> LLDBSwigPythonBreakpointCallbackFunction(
|
|
const char *python_function_name, const char *session_dictionary_name,
|
|
const lldb::StackFrameSP &sb_frame,
|
|
const lldb::BreakpointLocationSP &sb_bp_loc,
|
|
const lldb_private::StructuredDataImpl &args_impl);
|
|
|
|
static bool LLDBSwigPythonWatchpointCallbackFunction(
|
|
const char *python_function_name, const char *session_dictionary_name,
|
|
const lldb::StackFrameSP &sb_frame, const lldb::WatchpointSP &sb_wp);
|
|
|
|
static bool
|
|
LLDBSwigPythonFormatterCallbackFunction(const char *python_function_name,
|
|
const char *session_dictionary_name,
|
|
lldb::TypeImplSP type_impl_sp);
|
|
|
|
static bool LLDBSwigPythonCallTypeScript(
|
|
const char *python_function_name, const void *session_dictionary,
|
|
const lldb::ValueObjectSP &valobj_sp, void **pyfunct_wrapper,
|
|
const lldb::TypeSummaryOptionsSP &options_sp, std::string &retval);
|
|
|
|
static python::PythonObject
|
|
LLDBSwigPythonCreateSyntheticProvider(const char *python_class_name,
|
|
const char *session_dictionary_name,
|
|
const lldb::ValueObjectSP &valobj_sp);
|
|
|
|
static python::PythonObject
|
|
LLDBSwigPythonCreateCommandObject(const char *python_class_name,
|
|
const char *session_dictionary_name,
|
|
lldb::DebuggerSP debugger_sp);
|
|
|
|
static python::PythonObject LLDBSwigPythonCreateScriptedBreakpointResolver(
|
|
const char *python_class_name, const char *session_dictionary_name,
|
|
const StructuredDataImpl &args, const lldb::BreakpointSP &bkpt_sp);
|
|
|
|
static unsigned int
|
|
LLDBSwigPythonCallBreakpointResolver(void *implementor,
|
|
const char *method_name,
|
|
lldb_private::SymbolContext *sym_ctx);
|
|
|
|
static size_t LLDBSwigPython_CalculateNumChildren(PyObject *implementor,
|
|
uint32_t max);
|
|
|
|
static PyObject *LLDBSwigPython_GetChildAtIndex(PyObject *implementor,
|
|
uint32_t idx);
|
|
|
|
static int LLDBSwigPython_GetIndexOfChildWithName(PyObject *implementor,
|
|
const char *child_name);
|
|
|
|
static lldb::ValueObjectSP
|
|
LLDBSWIGPython_GetValueObjectSPFromSBValue(void *data);
|
|
|
|
static bool LLDBSwigPython_UpdateSynthProviderInstance(PyObject *implementor);
|
|
|
|
static bool
|
|
LLDBSwigPython_MightHaveChildrenSynthProviderInstance(PyObject *implementor);
|
|
|
|
static PyObject *
|
|
LLDBSwigPython_GetValueSynthProviderInstance(PyObject *implementor);
|
|
|
|
static bool
|
|
LLDBSwigPythonCallCommand(const char *python_function_name,
|
|
const char *session_dictionary_name,
|
|
lldb::DebuggerSP debugger, const char *args,
|
|
lldb_private::CommandReturnObject &cmd_retobj,
|
|
lldb::ExecutionContextRefSP exe_ctx_ref_sp);
|
|
|
|
static bool
|
|
LLDBSwigPythonCallCommandObject(PyObject *implementor,
|
|
lldb::DebuggerSP debugger, const char *args,
|
|
lldb_private::CommandReturnObject &cmd_retobj,
|
|
lldb::ExecutionContextRefSP exe_ctx_ref_sp);
|
|
static bool LLDBSwigPythonCallParsedCommandObject(
|
|
PyObject *implementor, lldb::DebuggerSP debugger,
|
|
StructuredDataImpl &args_impl,
|
|
lldb_private::CommandReturnObject &cmd_retobj,
|
|
lldb::ExecutionContextRefSP exe_ctx_ref_sp);
|
|
|
|
static std::optional<std::string>
|
|
LLDBSwigPythonGetRepeatCommandForScriptedCommand(PyObject *implementor,
|
|
std::string &command);
|
|
|
|
static StructuredData::DictionarySP
|
|
LLDBSwigPythonHandleArgumentCompletionForScriptedCommand(
|
|
PyObject *implementor, std::vector<llvm::StringRef> &args_impl,
|
|
size_t args_pos, size_t pos_in_arg);
|
|
|
|
static StructuredData::DictionarySP
|
|
LLDBSwigPythonHandleOptionArgumentCompletionForScriptedCommand(
|
|
PyObject *implementor, llvm::StringRef &long_option, size_t pos_in_arg);
|
|
|
|
static bool LLDBSwigPythonCallModuleInit(const char *python_module_name,
|
|
const char *session_dictionary_name,
|
|
lldb::DebuggerSP debugger);
|
|
|
|
static python::PythonObject
|
|
LLDBSWIGPythonCreateOSPlugin(const char *python_class_name,
|
|
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);
|
|
|
|
static std::optional<std::string>
|
|
LLDBSWIGPythonRunScriptKeywordThread(const char *python_function_name,
|
|
const char *session_dictionary_name,
|
|
lldb::ThreadSP thread);
|
|
|
|
static bool LLDBSWIGPythonRunScriptKeywordTarget(
|
|
const char *python_function_name, const char *session_dictionary_name,
|
|
const lldb::TargetSP &target, std::string &output);
|
|
|
|
static std::optional<std::string>
|
|
LLDBSWIGPythonRunScriptKeywordFrame(const char *python_function_name,
|
|
const char *session_dictionary_name,
|
|
lldb::StackFrameSP frame);
|
|
|
|
static bool LLDBSWIGPythonRunScriptKeywordValue(
|
|
const char *python_function_name, const char *session_dictionary_name,
|
|
const lldb::ValueObjectSP &value, std::string &output);
|
|
|
|
static void *
|
|
LLDBSWIGPython_GetDynamicSetting(void *module, const char *setting,
|
|
const lldb::TargetSP &target_sp);
|
|
};
|
|
|
|
void *LLDBSWIGPython_CastPyObjectToSBData(PyObject *data);
|
|
void *LLDBSWIGPython_CastPyObjectToSBBreakpoint(PyObject *data);
|
|
void *LLDBSWIGPython_CastPyObjectToSBAttachInfo(PyObject *data);
|
|
void *LLDBSWIGPython_CastPyObjectToSBLaunchInfo(PyObject *data);
|
|
void *LLDBSWIGPython_CastPyObjectToSBError(PyObject *data);
|
|
void *LLDBSWIGPython_CastPyObjectToSBEvent(PyObject *data);
|
|
void *LLDBSWIGPython_CastPyObjectToSBStream(PyObject *data);
|
|
void *LLDBSWIGPython_CastPyObjectToSBValue(PyObject *data);
|
|
void *LLDBSWIGPython_CastPyObjectToSBMemoryRegionInfo(PyObject *data);
|
|
void *LLDBSWIGPython_CastPyObjectToSBExecutionContext(PyObject *data);
|
|
} // namespace python
|
|
|
|
} // namespace lldb_private
|
|
|
|
#endif // LLDB_ENABLE_PYTHON
|
|
#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SWIGPYTHONBRIDGE_H
|