aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp')
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp190
1 files changed, 153 insertions, 37 deletions
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
index 3eee52184142..06e0d5bfa63f 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -6,16 +6,15 @@
//
//===----------------------------------------------------------------------===//
-#ifdef LLDB_DISABLE_PYTHON
+#include "lldb/Host/Config.h"
-// Python is disabled in this build
-
-#else
+#if LLDB_ENABLE_PYTHON
// LLDB Python header must be included first
#include "lldb-python.h"
#include "PythonDataObjects.h"
+#include "PythonReadline.h"
#include "ScriptInterpreterPythonImpl.h"
#include "lldb/API/SBFrame.h"
@@ -72,10 +71,28 @@ extern "C" void init_lldb(void);
// These prototypes are the Pythonic implementations of the required callbacks.
// Although these are scripting-language specific, their definition depends on
// the public API.
-extern "C" bool LLDBSwigPythonBreakpointCallbackFunction(
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
+
+// Disable warning C4190: 'LLDBSwigPythonBreakpointCallbackFunction' has
+// C-linkage specified, but returns UDT 'llvm::Expected<bool>' which is
+// incompatible with C
+#if _MSC_VER
+#pragma warning (push)
+#pragma warning (disable : 4190)
+#endif
+
+extern "C" 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::BreakpointLocationSP &sb_bp_loc, StructuredDataImpl *args_impl);
+
+#if _MSC_VER
+#pragma warning (pop)
+#endif
+
+#pragma clang diagnostic pop
extern "C" bool LLDBSwigPythonWatchpointCallbackFunction(
const char *python_function_name, const char *session_dictionary_name,
@@ -211,6 +228,22 @@ public:
InitializePythonHome();
+#ifdef LLDB_USE_LIBEDIT_READLINE_COMPAT_MODULE
+ // Python's readline is incompatible with libedit being linked into lldb.
+ // Provide a patched version local to the embedded interpreter.
+ bool ReadlinePatched = false;
+ for (auto *p = PyImport_Inittab; p->name != NULL; p++) {
+ if (strcmp(p->name, "readline") == 0) {
+ p->initfunc = initlldb_readline;
+ break;
+ }
+ }
+ if (!ReadlinePatched) {
+ PyImport_AppendInittab("readline", initlldb_readline);
+ ReadlinePatched = true;
+ }
+#endif
+
// Register _lldb as a built-in module.
PyImport_AppendInittab("_lldb", LLDBSwigPyInit);
@@ -552,8 +585,10 @@ void ScriptInterpreterPythonImpl::IOHandlerInputComplete(IOHandler &io_handler,
break;
data_up->user_source.SplitIntoLines(data);
+ StructuredData::ObjectSP empty_args_sp;
if (GenerateBreakpointCommandCallbackData(data_up->user_source,
- data_up->script_source)
+ data_up->script_source,
+ false)
.Success()) {
auto baton_sp = std::make_shared<BreakpointOptions::CommandBaton>(
std::move(data_up));
@@ -779,6 +814,32 @@ PythonDictionary &ScriptInterpreterPythonImpl::GetSysModuleDictionary() {
return m_sys_module_dict;
}
+llvm::Expected<unsigned>
+ScriptInterpreterPythonImpl::GetMaxPositionalArgumentsForCallable(
+ const llvm::StringRef &callable_name) {
+ if (callable_name.empty()) {
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "called with empty callable name.");
+ }
+ Locker py_lock(this, Locker::AcquireLock |
+ Locker::InitSession |
+ Locker::NoSTDIN);
+ auto dict = PythonModule::MainModule()
+ .ResolveName<PythonDictionary>(m_dictionary_name);
+ auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(
+ callable_name, dict);
+ if (!pfunc.IsAllocated()) {
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "can't find callable: %s", callable_name.str().c_str());
+ }
+ llvm::Expected<PythonCallable::ArgInfo> arg_info = pfunc.GetArgInfo();
+ if (!arg_info)
+ return arg_info.takeError();
+ return arg_info.get().max_positional_args;
+}
+
static std::string GenerateUniqueName(const char *base_name_wanted,
uint32_t &functions_counter,
const void *name_token = nullptr) {
@@ -1139,6 +1200,7 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLineWithReturn(
return true;
}
}
+ llvm_unreachable("Fully covered switch!");
}
Status ScriptInterpreterPythonImpl::ExecuteMultipleLines(
@@ -1186,24 +1248,56 @@ void ScriptInterpreterPythonImpl::CollectDataForBreakpointCommandCallback(
CommandReturnObject &result) {
m_active_io_handler = eIOHandlerBreakpoint;
m_debugger.GetCommandInterpreter().GetPythonCommandsFromIOHandler(
- " ", *this, true, &bp_options_vec);
+ " ", *this, &bp_options_vec);
}
void ScriptInterpreterPythonImpl::CollectDataForWatchpointCommandCallback(
WatchpointOptions *wp_options, CommandReturnObject &result) {
m_active_io_handler = eIOHandlerWatchpoint;
m_debugger.GetCommandInterpreter().GetPythonCommandsFromIOHandler(
- " ", *this, true, wp_options);
+ " ", *this, wp_options);
}
-void ScriptInterpreterPythonImpl::SetBreakpointCommandCallbackFunction(
- BreakpointOptions *bp_options, const char *function_name) {
+Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallbackFunction(
+ BreakpointOptions *bp_options, const char *function_name,
+ StructuredData::ObjectSP extra_args_sp) {
+ Status error;
// For now just cons up a oneliner that calls the provided function.
std::string oneliner("return ");
oneliner += function_name;
- oneliner += "(frame, bp_loc, internal_dict)";
- m_debugger.GetScriptInterpreter()->SetBreakpointCommandCallback(
- bp_options, oneliner.c_str());
+
+ llvm::Expected<unsigned> maybe_args =
+ GetMaxPositionalArgumentsForCallable(function_name);
+ if (!maybe_args) {
+ error.SetErrorStringWithFormat(
+ "could not get num args: %s",
+ llvm::toString(maybe_args.takeError()).c_str());
+ return error;
+ }
+ size_t max_args = *maybe_args;
+
+ bool uses_extra_args = false;
+ if (max_args >= 4) {
+ uses_extra_args = true;
+ oneliner += "(frame, bp_loc, extra_args, internal_dict)";
+ } else if (max_args >= 3) {
+ if (extra_args_sp) {
+ error.SetErrorString("cannot pass extra_args to a three argument callback"
+ );
+ return error;
+ }
+ uses_extra_args = false;
+ oneliner += "(frame, bp_loc, internal_dict)";
+ } else {
+ error.SetErrorStringWithFormat("expected 3 or 4 argument "
+ "function, %s can only take %zu",
+ function_name, max_args);
+ return error;
+ }
+
+ SetBreakpointCommandCallback(bp_options, oneliner.c_str(), extra_args_sp,
+ uses_extra_args);
+ return error;
}
Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback(
@@ -1211,7 +1305,8 @@ Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback(
std::unique_ptr<BreakpointOptions::CommandData> &cmd_data_up) {
Status error;
error = GenerateBreakpointCommandCallbackData(cmd_data_up->user_source,
- cmd_data_up->script_source);
+ cmd_data_up->script_source,
+ false);
if (error.Fail()) {
return error;
}
@@ -1222,11 +1317,17 @@ Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback(
return error;
}
-// Set a Python one-liner as the callback for the breakpoint.
Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback(
BreakpointOptions *bp_options, const char *command_body_text) {
- auto data_up = std::make_unique<CommandDataPython>();
+ return SetBreakpointCommandCallback(bp_options, command_body_text, {},false);
+}
+// Set a Python one-liner as the callback for the breakpoint.
+Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback(
+ BreakpointOptions *bp_options, const char *command_body_text,
+ StructuredData::ObjectSP extra_args_sp,
+ bool uses_extra_args) {
+ auto data_up = std::make_unique<CommandDataPython>(extra_args_sp);
// Split the command_body_text into lines, and pass that to
// GenerateBreakpointCommandCallbackData. That will wrap the body in an
// auto-generated function, and return the function name in script_source.
@@ -1234,7 +1335,8 @@ Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback(
data_up->user_source.SplitIntoLines(command_body_text);
Status error = GenerateBreakpointCommandCallbackData(data_up->user_source,
- data_up->script_source);
+ data_up->script_source,
+ uses_extra_args);
if (error.Success()) {
auto baton_sp =
std::make_shared<BreakpointOptions::CommandBaton>(std::move(data_up));
@@ -1771,8 +1873,7 @@ StructuredData::DictionarySP ScriptInterpreterPythonImpl::OSPlugin_CreateThread(
StructuredData::ObjectSP ScriptInterpreterPythonImpl::CreateScriptedThreadPlan(
const char *class_name, StructuredDataImpl *args_data,
- std::string &error_str,
- lldb::ThreadPlanSP thread_plan_sp) {
+ std::string &error_str, lldb::ThreadPlanSP thread_plan_sp) {
if (class_name == nullptr || class_name[0] == '\0')
return StructuredData::ObjectSP();
@@ -1956,8 +2057,7 @@ ScriptInterpreterPythonImpl::LoadPluginModule(const FileSpec &file_spec,
StructuredData::ObjectSP module_sp;
- if (LoadScriptingModule(file_spec.GetPath().c_str(), true, true, error,
- &module_sp))
+ if (LoadScriptingModule(file_spec.GetPath().c_str(), true, error, &module_sp))
return module_sp;
return StructuredData::ObjectSP();
@@ -2063,7 +2163,8 @@ bool ScriptInterpreterPythonImpl::GenerateTypeSynthClass(
}
Status ScriptInterpreterPythonImpl::GenerateBreakpointCommandCallbackData(
- StringList &user_input, std::string &output) {
+ StringList &user_input, std::string &output,
+ bool has_extra_args) {
static uint32_t num_created_functions = 0;
user_input.RemoveBlankLines();
StreamString sstr;
@@ -2075,8 +2176,12 @@ Status ScriptInterpreterPythonImpl::GenerateBreakpointCommandCallbackData(
std::string auto_generated_function_name(GenerateUniqueName(
"lldb_autogen_python_bp_callback_func_", num_created_functions));
- sstr.Printf("def %s (frame, bp_loc, internal_dict):",
- auto_generated_function_name.c_str());
+ if (has_extra_args)
+ sstr.Printf("def %s (frame, bp_loc, extra_args, internal_dict):",
+ auto_generated_function_name.c_str());
+ else
+ sstr.Printf("def %s (frame, bp_loc, internal_dict):",
+ auto_generated_function_name.c_str());
error = GenerateFunction(sstr.GetData(), user_input);
if (!error.Success())
@@ -2193,10 +2298,26 @@ bool ScriptInterpreterPythonImpl::BreakpointCallbackFunction(
Locker py_lock(python_interpreter, Locker::AcquireLock |
Locker::InitSession |
Locker::NoSTDIN);
- ret_val = LLDBSwigPythonBreakpointCallbackFunction(
- python_function_name,
- python_interpreter->m_dictionary_name.c_str(), stop_frame_sp,
- bp_loc_sp);
+ Expected<bool> maybe_ret_val =
+ LLDBSwigPythonBreakpointCallbackFunction(
+ python_function_name,
+ python_interpreter->m_dictionary_name.c_str(), stop_frame_sp,
+ bp_loc_sp, bp_option_data->m_extra_args_up.get());
+
+ if (!maybe_ret_val) {
+
+ llvm::handleAllErrors(
+ maybe_ret_val.takeError(),
+ [&](PythonException &E) {
+ debugger.GetErrorStream() << E.ReadBacktrace();
+ },
+ [&](const llvm::ErrorInfoBase &E) {
+ debugger.GetErrorStream() << E.message();
+ });
+
+ } else {
+ ret_val = maybe_ret_val.get();
+ }
}
return ret_val;
}
@@ -2615,8 +2736,8 @@ uint64_t replace_all(std::string &str, const std::string &oldStr,
}
bool ScriptInterpreterPythonImpl::LoadScriptingModule(
- const char *pathname, bool can_reload, bool init_session,
- lldb_private::Status &error, StructuredData::ObjectSP *module_sp) {
+ const char *pathname, bool init_session, lldb_private::Status &error,
+ StructuredData::ObjectSP *module_sp) {
if (!pathname || !pathname[0]) {
error.SetErrorString("invalid pathname");
return false;
@@ -2716,11 +2837,6 @@ bool ScriptInterpreterPythonImpl::LoadScriptingModule(
bool was_imported = (was_imported_globally || was_imported_locally);
- if (was_imported && !can_reload) {
- error.SetErrorString("module already imported");
- return false;
- }
-
// now actually do the import
command_stream.Clear();
@@ -3171,4 +3287,4 @@ void ScriptInterpreterPythonImpl::AddToSysPath(AddLocation location,
//
// void ScriptInterpreterPythonImpl::Terminate() { Py_Finalize (); }
-#endif // LLDB_DISABLE_PYTHON
+#endif