diff options
Diffstat (limited to 'lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp')
-rw-r--r-- | lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp | 190 |
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 |