diff options
Diffstat (limited to 'source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp')
-rw-r--r-- | source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp | 567 |
1 files changed, 241 insertions, 326 deletions
diff --git a/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index 2d2b68ceaaa6b..3eee52184142d 100644 --- a/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -16,7 +16,6 @@ #include "lldb-python.h" #include "PythonDataObjects.h" -#include "PythonExceptionState.h" #include "ScriptInterpreterPythonImpl.h" #include "lldb/API/SBFrame.h" @@ -45,6 +44,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/FormatAdapters.h" #include <memory> #include <mutex> @@ -54,6 +54,8 @@ using namespace lldb; using namespace lldb_private; +using namespace lldb_private::python; +using llvm::Expected; // Defined in the SWIG source file #if PY_MAJOR_VERSION >= 3 @@ -96,6 +98,8 @@ LLDBSwigPythonCreateCommandObject(const char *python_class_name, extern "C" void *LLDBSwigPythonCreateScriptedThreadPlan( const char *python_class_name, const char *session_dictionary_name, + StructuredDataImpl *args_data, + std::string &error_string, const lldb::ThreadPlanSP &thread_plan_sp); extern "C" bool LLDBSWIGPythonCallThreadPlan(void *implementor, @@ -302,39 +306,26 @@ void ScriptInterpreterPython::ComputePythonDirForApple( auto rend = llvm::sys::path::rend(path_ref); auto framework = std::find(rbegin, rend, "LLDB.framework"); if (framework == rend) { - ComputePythonDirForPosix(path); + ComputePythonDir(path); return; } path.resize(framework - rend); llvm::sys::path::append(path, style, "LLDB.framework", "Resources", "Python"); } -void ScriptInterpreterPython::ComputePythonDirForPosix( +void ScriptInterpreterPython::ComputePythonDir( llvm::SmallVectorImpl<char> &path) { - auto style = llvm::sys::path::Style::posix; -#if defined(LLDB_PYTHON_RELATIVE_LIBDIR) // Build the path by backing out of the lib dir, then building with whatever // the real python interpreter uses. (e.g. lib for most, lib64 on RHEL - // x86_64). - llvm::sys::path::remove_filename(path, style); - llvm::sys::path::append(path, style, LLDB_PYTHON_RELATIVE_LIBDIR); -#else - llvm::sys::path::append(path, style, - "python" + llvm::Twine(PY_MAJOR_VERSION) + "." + - llvm::Twine(PY_MINOR_VERSION), - "site-packages"); -#endif -} - -void ScriptInterpreterPython::ComputePythonDirForWindows( - llvm::SmallVectorImpl<char> &path) { - auto style = llvm::sys::path::Style::windows; - llvm::sys::path::remove_filename(path, style); - llvm::sys::path::append(path, style, "lib", "site-packages"); + // x86_64, or bin on Windows). + llvm::sys::path::remove_filename(path); + llvm::sys::path::append(path, LLDB_PYTHON_RELATIVE_LIBDIR); +#if defined(_WIN32) // This will be injected directly through FileSpec.GetDirectory().SetString(), // so we need to normalize manually. std::replace(path.begin(), path.end(), '\\', '/'); +#endif } FileSpec ScriptInterpreterPython::GetPythonDir() { @@ -347,10 +338,8 @@ FileSpec ScriptInterpreterPython::GetPythonDir() { #if defined(__APPLE__) ComputePythonDirForApple(path); -#elif defined(_WIN32) - ComputePythonDirForWindows(path); #else - ComputePythonDirForPosix(path); + ComputePythonDir(path); #endif spec.GetDirectory().SetString(path); return spec; @@ -382,7 +371,7 @@ void ScriptInterpreterPython::Terminate() {} ScriptInterpreterPythonImpl::Locker::Locker( ScriptInterpreterPythonImpl *py_interpreter, uint16_t on_entry, - uint16_t on_leave, FILE *in, FILE *out, FILE *err) + uint16_t on_leave, FileSP in, FileSP out, FileSP err) : ScriptInterpreterLocker(), m_teardown_session((on_leave & TearDownSession) == TearDownSession), m_python_interpreter(py_interpreter) { @@ -412,8 +401,8 @@ bool ScriptInterpreterPythonImpl::Locker::DoAcquireLock() { } bool ScriptInterpreterPythonImpl::Locker::DoInitSession(uint16_t on_entry_flags, - FILE *in, FILE *out, - FILE *err) { + FileSP in, FileSP out, + FileSP err) { if (!m_python_interpreter) return false; return m_python_interpreter->EnterSession(on_entry_flags, in, out, err); @@ -448,9 +437,9 @@ ScriptInterpreterPythonImpl::ScriptInterpreterPythonImpl(Debugger &debugger) m_sys_module_dict(PyInitialValue::Invalid), m_run_one_line_function(), m_run_one_line_str_global(), m_dictionary_name(m_debugger.GetInstanceName().AsCString()), - m_terminal_state(), m_active_io_handler(eIOHandlerNone), - m_session_is_active(false), m_pty_slave_is_open(false), - m_valid_session(true), m_lock_count(0), m_command_thread_state(nullptr) { + m_active_io_handler(eIOHandlerNone), m_session_is_active(false), + m_pty_slave_is_open(false), m_valid_session(true), m_lock_count(0), + m_command_thread_state(nullptr) { InitializePrivate(); m_dictionary_name.append("_dict"); @@ -535,7 +524,7 @@ def function (frame, bp_loc, internal_dict): } if (instructions) { - StreamFileSP output_sp(io_handler.GetOutputStreamFile()); + StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); if (output_sp && interactive) { output_sp->PutCString(instructions); output_sp->Flush(); @@ -558,7 +547,7 @@ void ScriptInterpreterPythonImpl::IOHandlerInputComplete(IOHandler &io_handler, if (!bp_options) continue; - auto data_up = llvm::make_unique<CommandDataPython>(); + auto data_up = std::make_unique<CommandDataPython>(); if (!data_up) break; data_up->user_source.SplitIntoLines(data); @@ -571,7 +560,7 @@ void ScriptInterpreterPythonImpl::IOHandlerInputComplete(IOHandler &io_handler, bp_options->SetCallback( ScriptInterpreterPythonImpl::BreakpointCallbackFunction, baton_sp); } else if (!batch_mode) { - StreamFileSP error_sp = io_handler.GetErrorStreamFile(); + StreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); if (error_sp) { error_sp->Printf("Warning: No command attached to breakpoint.\n"); error_sp->Flush(); @@ -583,7 +572,7 @@ void ScriptInterpreterPythonImpl::IOHandlerInputComplete(IOHandler &io_handler, case eIOHandlerWatchpoint: { WatchpointOptions *wp_options = (WatchpointOptions *)io_handler.GetUserData(); - auto data_up = llvm::make_unique<WatchpointOptions::CommandData>(); + auto data_up = std::make_unique<WatchpointOptions::CommandData>(); data_up->user_source.SplitIntoLines(data); if (GenerateWatchpointCommandCallbackData(data_up->user_source, @@ -593,7 +582,7 @@ void ScriptInterpreterPythonImpl::IOHandlerInputComplete(IOHandler &io_handler, wp_options->SetCallback( ScriptInterpreterPythonImpl::WatchpointCallbackFunction, baton_sp); } else if (!batch_mode) { - StreamFileSP error_sp = io_handler.GetErrorStreamFile(); + StreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); if (error_sp) { error_sp->Printf("Warning: No command attached to breakpoint.\n"); error_sp->Flush(); @@ -609,29 +598,15 @@ ScriptInterpreterPythonImpl::CreateInstance(Debugger &debugger) { return std::make_shared<ScriptInterpreterPythonImpl>(debugger); } -void ScriptInterpreterPythonImpl::ResetOutputFileHandle(FILE *fh) {} - -void ScriptInterpreterPythonImpl::SaveTerminalState(int fd) { - // Python mucks with the terminal state of STDIN. If we can possibly avoid - // this by setting the file handles up correctly prior to entering the - // interpreter we should. For now we save and restore the terminal state on - // the input file handle. - m_terminal_state.Save(fd, false); -} - -void ScriptInterpreterPythonImpl::RestoreTerminalState() { - // Python mucks with the terminal state of STDIN. If we can possibly avoid - // this by setting the file handles up correctly prior to entering the - // interpreter we should. For now we save and restore the terminal state on - // the input file handle. - m_terminal_state.Restore(); -} - void ScriptInterpreterPythonImpl::LeaveSession() { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SCRIPT)); if (log) log->PutCString("ScriptInterpreterPythonImpl::LeaveSession()"); + // Unset the LLDB global variables. + PyRun_SimpleString("lldb.debugger = None; lldb.target = None; lldb.process " + "= None; lldb.thread = None; lldb.frame = None"); + // checking that we have a valid thread state - since we use our own // threading and locking in some (rare) cases during cleanup Python may end // up believing we have no thread state and PyImport_AddModule will crash if @@ -662,45 +637,52 @@ void ScriptInterpreterPythonImpl::LeaveSession() { m_session_is_active = false; } -bool ScriptInterpreterPythonImpl::SetStdHandle(File &file, const char *py_name, - PythonFile &save_file, +bool ScriptInterpreterPythonImpl::SetStdHandle(FileSP file_sp, + const char *py_name, + PythonObject &save_file, const char *mode) { - if (file.IsValid()) { - // Flush the file before giving it to python to avoid interleaved output. - file.Flush(); + if (!file_sp || !*file_sp) { + save_file.Reset(); + return false; + } + File &file = *file_sp; - PythonDictionary &sys_module_dict = GetSysModuleDictionary(); + // Flush the file before giving it to python to avoid interleaved output. + file.Flush(); - save_file = sys_module_dict.GetItemForKey(PythonString(py_name)) - .AsType<PythonFile>(); + PythonDictionary &sys_module_dict = GetSysModuleDictionary(); - PythonFile new_file(file, mode); - sys_module_dict.SetItemForKey(PythonString(py_name), new_file); - return true; - } else - save_file.Reset(); - return false; + auto new_file = PythonFile::FromFile(file, mode); + if (!new_file) { + llvm::consumeError(new_file.takeError()); + return false; + } + + save_file = sys_module_dict.GetItemForKey(PythonString(py_name)); + + sys_module_dict.SetItemForKey(PythonString(py_name), new_file.get()); + return true; } bool ScriptInterpreterPythonImpl::EnterSession(uint16_t on_entry_flags, - FILE *in, FILE *out, FILE *err) { + FileSP in_sp, FileSP out_sp, + FileSP err_sp) { // If we have already entered the session, without having officially 'left' // it, then there is no need to 'enter' it again. Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SCRIPT)); if (m_session_is_active) { - if (log) - log->Printf( - "ScriptInterpreterPythonImpl::EnterSession(on_entry_flags=0x%" PRIx16 - ") session is already active, returning without doing anything", - on_entry_flags); + LLDB_LOGF( + log, + "ScriptInterpreterPythonImpl::EnterSession(on_entry_flags=0x%" PRIx16 + ") session is already active, returning without doing anything", + on_entry_flags); return false; } - if (log) - log->Printf( - "ScriptInterpreterPythonImpl::EnterSession(on_entry_flags=0x%" PRIx16 - ")", - on_entry_flags); + LLDB_LOGF( + log, + "ScriptInterpreterPythonImpl::EnterSession(on_entry_flags=0x%" PRIx16 ")", + on_entry_flags); m_session_is_active = true; @@ -733,33 +715,29 @@ bool ScriptInterpreterPythonImpl::EnterSession(uint16_t on_entry_flags, PythonDictionary &sys_module_dict = GetSysModuleDictionary(); if (sys_module_dict.IsValid()) { - File in_file(in, false); - File out_file(out, false); - File err_file(err, false); - - lldb::StreamFileSP in_sp; - lldb::StreamFileSP out_sp; - lldb::StreamFileSP err_sp; - if (!in_file.IsValid() || !out_file.IsValid() || !err_file.IsValid()) - m_debugger.AdoptTopIOHandlerFilesIfInvalid(in_sp, out_sp, err_sp); + lldb::FileSP top_in_sp; + lldb::StreamFileSP top_out_sp, top_err_sp; + if (!in_sp || !out_sp || !err_sp || !*in_sp || !*out_sp || !*err_sp) + m_debugger.AdoptTopIOHandlerFilesIfInvalid(top_in_sp, top_out_sp, + top_err_sp); if (on_entry_flags & Locker::NoSTDIN) { m_saved_stdin.Reset(); } else { - if (!SetStdHandle(in_file, "stdin", m_saved_stdin, "r")) { - if (in_sp) - SetStdHandle(in_sp->GetFile(), "stdin", m_saved_stdin, "r"); + if (!SetStdHandle(in_sp, "stdin", m_saved_stdin, "r")) { + if (top_in_sp) + SetStdHandle(top_in_sp, "stdin", m_saved_stdin, "r"); } } - if (!SetStdHandle(out_file, "stdout", m_saved_stdout, "w")) { - if (out_sp) - SetStdHandle(out_sp->GetFile(), "stdout", m_saved_stdout, "w"); + if (!SetStdHandle(out_sp, "stdout", m_saved_stdout, "w")) { + if (top_out_sp) + SetStdHandle(top_out_sp->GetFileSP(), "stdout", m_saved_stdout, "w"); } - if (!SetStdHandle(err_file, "stderr", m_saved_stderr, "w")) { - if (err_sp) - SetStdHandle(err_sp->GetFile(), "stderr", m_saved_stderr, "w"); + if (!SetStdHandle(err_sp, "stderr", m_saved_stderr, "w")) { + if (top_err_sp) + SetStdHandle(top_err_sp->GetFileSP(), "stderr", m_saved_stderr, "w"); } } @@ -769,9 +747,9 @@ bool ScriptInterpreterPythonImpl::EnterSession(uint16_t on_entry_flags, return true; } -PythonObject &ScriptInterpreterPythonImpl::GetMainModule() { +PythonModule &ScriptInterpreterPythonImpl::GetMainModule() { if (!m_main_module.IsValid()) - m_main_module.Reset(PyRefType::Borrowed, PyImport_AddModule("__main__")); + m_main_module = unwrapIgnoringErrors(PythonModule::Import("__main__")); return m_main_module; } @@ -788,19 +766,16 @@ PythonDictionary &ScriptInterpreterPythonImpl::GetSessionDictionary() { if (!main_dict.IsValid()) return m_session_dict; - PythonObject item = main_dict.GetItemForKey(PythonString(m_dictionary_name)); - m_session_dict.Reset(PyRefType::Borrowed, item.get()); + m_session_dict = unwrapIgnoringErrors( + As<PythonDictionary>(main_dict.GetItem(m_dictionary_name))); return m_session_dict; } PythonDictionary &ScriptInterpreterPythonImpl::GetSysModuleDictionary() { if (m_sys_module_dict.IsValid()) return m_sys_module_dict; - - PythonObject sys_module(PyRefType::Borrowed, PyImport_AddModule("sys")); - if (sys_module.IsValid()) - m_sys_module_dict.Reset(PyRefType::Borrowed, - PyModule_GetDict(sys_module.get())); + PythonModule sys_module = unwrapIgnoringErrors(PythonModule::Import("sys")); + m_sys_module_dict = sys_module.GetDictionary(); return m_sys_module_dict; } @@ -867,7 +842,7 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLine( // directly down to Python. Debugger &debugger = m_debugger; - StreamFileSP input_file_sp; + FileSP input_file_sp; StreamFileSP output_file_sp; StreamFileSP error_file_sp; Communication output_comm( @@ -875,7 +850,7 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLine( bool join_read_thread = false; if (options.GetEnableIO()) { if (result) { - input_file_sp = debugger.GetInputFile(); + input_file_sp = debugger.GetInputFileSP(); // Set output to a temporary file so we can forward the results on to // the result object @@ -906,9 +881,9 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLine( ::setbuf(outfile_handle, nullptr); result->SetImmediateOutputFile( - debugger.GetOutputFile()->GetFile().GetStream()); + debugger.GetOutputStream().GetFileSP()); result->SetImmediateErrorFile( - debugger.GetErrorFile()->GetFile().GetStream()); + debugger.GetErrorStream().GetFileSP()); } } } @@ -916,22 +891,26 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLine( debugger.AdoptTopIOHandlerFilesIfInvalid(input_file_sp, output_file_sp, error_file_sp); } else { - input_file_sp = std::make_shared<StreamFile>(); - FileSystem::Instance().Open(input_file_sp->GetFile(), + auto nullin = FileSystem::Instance().Open( FileSpec(FileSystem::DEV_NULL), File::eOpenOptionRead); - - output_file_sp = std::make_shared<StreamFile>(); - FileSystem::Instance().Open(output_file_sp->GetFile(), + auto nullout = FileSystem::Instance().Open( FileSpec(FileSystem::DEV_NULL), File::eOpenOptionWrite); - - error_file_sp = output_file_sp; + if (!nullin) { + result->AppendErrorWithFormatv("failed to open /dev/null: {0}\n", + llvm::fmt_consume(nullin.takeError())); + return false; + } + if (!nullout) { + result->AppendErrorWithFormatv("failed to open /dev/null: {0}\n", + llvm::fmt_consume(nullout.takeError())); + return false; + } + input_file_sp = std::move(nullin.get()); + error_file_sp = output_file_sp = std::make_shared<StreamFile>(std::move(nullout.get())); } - FILE *in_file = input_file_sp->GetFile().GetStream(); - FILE *out_file = output_file_sp->GetFile().GetStream(); - FILE *err_file = error_file_sp->GetFile().GetStream(); bool success = false; { // WARNING! It's imperative that this RAII scope be as tight as @@ -947,8 +926,8 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLine( Locker::AcquireLock | Locker::InitSession | (options.GetSetLLDBGlobals() ? Locker::InitGlobals : 0) | ((result && result->GetInteractive()) ? 0 : Locker::NoSTDIN), - Locker::FreeAcquiredLock | Locker::TearDownSession, in_file, out_file, - err_file); + Locker::FreeAcquiredLock | Locker::TearDownSession, input_file_sp, + output_file_sp->GetFileSP(), error_file_sp->GetFileSP()); // Find the correct script interpreter dictionary in the main module. PythonDictionary &session_dict = GetSessionDictionary(); @@ -975,9 +954,8 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLine( } // Flush our output and error file handles - ::fflush(out_file); - if (out_file != err_file) - ::fflush(err_file); + output_file_sp->Flush(); + error_file_sp->Flush(); } if (join_read_thread) { @@ -1020,7 +998,7 @@ void ScriptInterpreterPythonImpl::ExecuteInterpreterLoop() { // a running interpreter loop inside the already running Python interpreter // loop, so we won't do it. - if (!debugger.GetInputFile()->GetFile().IsValid()) + if (!debugger.GetInputFile().IsValid()) return; IOHandlerSP io_handler_sp(new IOHandlerPythonInterpreter(debugger, this)); @@ -1040,19 +1018,19 @@ bool ScriptInterpreterPythonImpl::Interrupt() { long tid = state->thread_id; PyThreadState_Swap(state); int num_threads = PyThreadState_SetAsyncExc(tid, PyExc_KeyboardInterrupt); - if (log) - log->Printf("ScriptInterpreterPythonImpl::Interrupt() sending " - "PyExc_KeyboardInterrupt (tid = %li, num_threads = %i)...", - tid, num_threads); + LLDB_LOGF(log, + "ScriptInterpreterPythonImpl::Interrupt() sending " + "PyExc_KeyboardInterrupt (tid = %li, num_threads = %i)...", + tid, num_threads); return true; } } - if (log) - log->Printf( - "ScriptInterpreterPythonImpl::Interrupt() python code not running, " - "can't interrupt"); + LLDB_LOGF(log, + "ScriptInterpreterPythonImpl::Interrupt() python code not running, " + "can't interrupt"); return false; } + bool ScriptInterpreterPythonImpl::ExecuteOneLineWithReturn( llvm::StringRef in_string, ScriptInterpreter::ScriptReturnType return_type, void *ret_value, const ExecuteScriptOptions &options) { @@ -1063,152 +1041,111 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLineWithReturn( Locker::NoSTDIN, Locker::FreeAcquiredLock | Locker::TearDownSession); - PythonObject py_return; - PythonObject &main_module = GetMainModule(); - PythonDictionary globals(PyRefType::Borrowed, - PyModule_GetDict(main_module.get())); - PythonObject py_error; - bool ret_success = false; - int success; + PythonModule &main_module = GetMainModule(); + PythonDictionary globals = main_module.GetDictionary(); PythonDictionary locals = GetSessionDictionary(); - - if (!locals.IsValid()) { - locals.Reset( - PyRefType::Owned, - PyObject_GetAttrString(globals.get(), m_dictionary_name.c_str())); - } - + if (!locals.IsValid()) + locals = unwrapIgnoringErrors( + As<PythonDictionary>(globals.GetAttribute(m_dictionary_name))); if (!locals.IsValid()) locals = globals; - py_error.Reset(PyRefType::Borrowed, PyErr_Occurred()); - if (py_error.IsValid()) - PyErr_Clear(); - - std::string as_string = in_string.str(); - { // scope for PythonInputReaderManager - // PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL); - py_return.Reset(PyRefType::Owned, - PyRun_String(as_string.c_str(), Py_eval_input, - globals.get(), locals.get())); - if (!py_return.IsValid()) { - py_error.Reset(PyRefType::Borrowed, PyErr_Occurred()); - if (py_error.IsValid()) - PyErr_Clear(); - - py_return.Reset(PyRefType::Owned, - PyRun_String(as_string.c_str(), Py_single_input, - globals.get(), locals.get())); - } + Expected<PythonObject> maybe_py_return = + runStringOneLine(in_string, globals, locals); + + if (!maybe_py_return) { + llvm::handleAllErrors( + maybe_py_return.takeError(), + [&](PythonException &E) { + E.Restore(); + if (options.GetMaskoutErrors()) { + if (E.Matches(PyExc_SyntaxError)) { + PyErr_Print(); + } + PyErr_Clear(); + } + }, + [](const llvm::ErrorInfoBase &E) {}); + return false; } - if (py_return.IsValid()) { - switch (return_type) { - case eScriptReturnTypeCharPtr: // "char *" - { - const char format[3] = "s#"; - success = PyArg_Parse(py_return.get(), format, (char **)ret_value); - break; - } - case eScriptReturnTypeCharStrOrNone: // char* or NULL if py_return == - // Py_None - { - const char format[3] = "z"; - success = PyArg_Parse(py_return.get(), format, (char **)ret_value); - break; - } - case eScriptReturnTypeBool: { - const char format[2] = "b"; - success = PyArg_Parse(py_return.get(), format, (bool *)ret_value); - break; - } - case eScriptReturnTypeShortInt: { - const char format[2] = "h"; - success = PyArg_Parse(py_return.get(), format, (short *)ret_value); - break; - } - case eScriptReturnTypeShortIntUnsigned: { - const char format[2] = "H"; - success = - PyArg_Parse(py_return.get(), format, (unsigned short *)ret_value); - break; - } - case eScriptReturnTypeInt: { - const char format[2] = "i"; - success = PyArg_Parse(py_return.get(), format, (int *)ret_value); - break; - } - case eScriptReturnTypeIntUnsigned: { - const char format[2] = "I"; - success = PyArg_Parse(py_return.get(), format, (unsigned int *)ret_value); - break; - } - case eScriptReturnTypeLongInt: { - const char format[2] = "l"; - success = PyArg_Parse(py_return.get(), format, (long *)ret_value); - break; - } - case eScriptReturnTypeLongIntUnsigned: { - const char format[2] = "k"; - success = - PyArg_Parse(py_return.get(), format, (unsigned long *)ret_value); - break; - } - case eScriptReturnTypeLongLong: { - const char format[2] = "L"; - success = PyArg_Parse(py_return.get(), format, (long long *)ret_value); - break; - } - case eScriptReturnTypeLongLongUnsigned: { - const char format[2] = "K"; - success = - PyArg_Parse(py_return.get(), format, (unsigned long long *)ret_value); - break; - } - case eScriptReturnTypeFloat: { - const char format[2] = "f"; - success = PyArg_Parse(py_return.get(), format, (float *)ret_value); - break; - } - case eScriptReturnTypeDouble: { - const char format[2] = "d"; - success = PyArg_Parse(py_return.get(), format, (double *)ret_value); - break; - } - case eScriptReturnTypeChar: { - const char format[2] = "c"; - success = PyArg_Parse(py_return.get(), format, (char *)ret_value); - break; - } - case eScriptReturnTypeOpaqueObject: { - success = true; - PyObject *saved_value = py_return.get(); - Py_XINCREF(saved_value); - *((PyObject **)ret_value) = saved_value; - break; - } - } + PythonObject py_return = std::move(maybe_py_return.get()); + assert(py_return.IsValid()); - ret_success = success; + switch (return_type) { + case eScriptReturnTypeCharPtr: // "char *" + { + const char format[3] = "s#"; + return PyArg_Parse(py_return.get(), format, (char **)ret_value); + } + case eScriptReturnTypeCharStrOrNone: // char* or NULL if py_return == + // Py_None + { + const char format[3] = "z"; + return PyArg_Parse(py_return.get(), format, (char **)ret_value); + } + case eScriptReturnTypeBool: { + const char format[2] = "b"; + return PyArg_Parse(py_return.get(), format, (bool *)ret_value); + } + case eScriptReturnTypeShortInt: { + const char format[2] = "h"; + return PyArg_Parse(py_return.get(), format, (short *)ret_value); + } + case eScriptReturnTypeShortIntUnsigned: { + const char format[2] = "H"; + return PyArg_Parse(py_return.get(), format, (unsigned short *)ret_value); + } + case eScriptReturnTypeInt: { + const char format[2] = "i"; + return PyArg_Parse(py_return.get(), format, (int *)ret_value); + } + case eScriptReturnTypeIntUnsigned: { + const char format[2] = "I"; + return PyArg_Parse(py_return.get(), format, (unsigned int *)ret_value); + } + case eScriptReturnTypeLongInt: { + const char format[2] = "l"; + return PyArg_Parse(py_return.get(), format, (long *)ret_value); + } + case eScriptReturnTypeLongIntUnsigned: { + const char format[2] = "k"; + return PyArg_Parse(py_return.get(), format, (unsigned long *)ret_value); + } + case eScriptReturnTypeLongLong: { + const char format[2] = "L"; + return PyArg_Parse(py_return.get(), format, (long long *)ret_value); + } + case eScriptReturnTypeLongLongUnsigned: { + const char format[2] = "K"; + return PyArg_Parse(py_return.get(), format, + (unsigned long long *)ret_value); + } + case eScriptReturnTypeFloat: { + const char format[2] = "f"; + return PyArg_Parse(py_return.get(), format, (float *)ret_value); + } + case eScriptReturnTypeDouble: { + const char format[2] = "d"; + return PyArg_Parse(py_return.get(), format, (double *)ret_value); + } + case eScriptReturnTypeChar: { + const char format[2] = "c"; + return PyArg_Parse(py_return.get(), format, (char *)ret_value); + } + case eScriptReturnTypeOpaqueObject: { + *((PyObject **)ret_value) = py_return.release(); + return true; } - - py_error.Reset(PyRefType::Borrowed, PyErr_Occurred()); - if (py_error.IsValid()) { - ret_success = false; - if (options.GetMaskoutErrors()) { - if (PyErr_GivenExceptionMatches(py_error.get(), PyExc_SyntaxError)) - PyErr_Print(); - PyErr_Clear(); - } } - - return ret_success; } Status ScriptInterpreterPythonImpl::ExecuteMultipleLines( const char *in_string, const ExecuteScriptOptions &options) { - Status error; + + if (in_string == nullptr) + return Status(); Locker locker(this, Locker::AcquireLock | Locker::InitSession | @@ -1216,52 +1153,32 @@ Status ScriptInterpreterPythonImpl::ExecuteMultipleLines( Locker::NoSTDIN, Locker::FreeAcquiredLock | Locker::TearDownSession); - PythonObject return_value; - PythonObject &main_module = GetMainModule(); - PythonDictionary globals(PyRefType::Borrowed, - PyModule_GetDict(main_module.get())); - PythonObject py_error; + PythonModule &main_module = GetMainModule(); + PythonDictionary globals = main_module.GetDictionary(); PythonDictionary locals = GetSessionDictionary(); - if (!locals.IsValid()) - locals.Reset( - PyRefType::Owned, - PyObject_GetAttrString(globals.get(), m_dictionary_name.c_str())); - + locals = unwrapIgnoringErrors( + As<PythonDictionary>(globals.GetAttribute(m_dictionary_name))); if (!locals.IsValid()) locals = globals; - py_error.Reset(PyRefType::Borrowed, PyErr_Occurred()); - if (py_error.IsValid()) - PyErr_Clear(); + Expected<PythonObject> return_value = + runStringMultiLine(in_string, globals, locals); - if (in_string != nullptr) { - PythonObject code_object; - code_object.Reset(PyRefType::Owned, - Py_CompileString(in_string, "temp.py", Py_file_input)); - - if (code_object.IsValid()) { -// In Python 2.x, PyEval_EvalCode takes a PyCodeObject, but in Python 3.x, it -// takes a PyObject. They are convertible (hence the function -// PyCode_Check(PyObject*), so we have to do the cast for Python 2.x -#if PY_MAJOR_VERSION >= 3 - PyObject *py_code_obj = code_object.get(); -#else - PyCodeObject *py_code_obj = - reinterpret_cast<PyCodeObject *>(code_object.get()); -#endif - return_value.Reset( - PyRefType::Owned, - PyEval_EvalCode(py_code_obj, globals.get(), locals.get())); - } + if (!return_value) { + llvm::Error error = + llvm::handleErrors(return_value.takeError(), [&](PythonException &E) { + llvm::Error error = llvm::createStringError( + llvm::inconvertibleErrorCode(), E.ReadBacktrace()); + if (!options.GetMaskoutErrors()) + E.Restore(); + return error; + }); + return Status(std::move(error)); } - PythonExceptionState exception_state(!options.GetMaskoutErrors()); - if (exception_state.IsError()) - error.SetErrorString(exception_state.Format().c_str()); - - return error; + return Status(); } void ScriptInterpreterPythonImpl::CollectDataForBreakpointCommandCallback( @@ -1308,7 +1225,7 @@ Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback( // 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 = llvm::make_unique<CommandDataPython>(); + auto data_up = std::make_unique<CommandDataPython>(); // Split the command_body_text into lines, and pass that to // GenerateBreakpointCommandCallbackData. That will wrap the body in an @@ -1331,7 +1248,7 @@ Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback( // Set a Python one-liner as the callback for the watchpoint. void ScriptInterpreterPythonImpl::SetWatchpointCommandCallback( WatchpointOptions *wp_options, const char *oneliner) { - auto data_up = llvm::make_unique<WatchpointOptions::CommandData>(); + auto data_up = std::make_unique<WatchpointOptions::CommandData>(); // It's necessary to set both user_source and script_source to the oneliner. // The former is used to generate callback description (as in watchpoint @@ -1853,12 +1770,14 @@ StructuredData::DictionarySP ScriptInterpreterPythonImpl::OSPlugin_CreateThread( } StructuredData::ObjectSP ScriptInterpreterPythonImpl::CreateScriptedThreadPlan( - const char *class_name, lldb::ThreadPlanSP thread_plan_sp) { + const char *class_name, StructuredDataImpl *args_data, + std::string &error_str, + lldb::ThreadPlanSP thread_plan_sp) { if (class_name == nullptr || class_name[0] == '\0') return StructuredData::ObjectSP(); if (!thread_plan_sp.get()) - return StructuredData::ObjectSP(); + return {}; Debugger &debugger = thread_plan_sp->GetTarget().GetDebugger(); ScriptInterpreter *script_interpreter = debugger.GetScriptInterpreter(); @@ -1866,17 +1785,18 @@ StructuredData::ObjectSP ScriptInterpreterPythonImpl::CreateScriptedThreadPlan( static_cast<ScriptInterpreterPythonImpl *>(script_interpreter); if (!script_interpreter) - return StructuredData::ObjectSP(); + return {}; void *ret_val; { Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - ret_val = LLDBSwigPythonCreateScriptedThreadPlan( class_name, python_interpreter->m_dictionary_name.c_str(), - thread_plan_sp); + args_data, error_str, thread_plan_sp); + if (!ret_val) + return {}; } return StructuredData::ObjectSP(new StructuredPythonObject(ret_val)); @@ -2052,15 +1972,22 @@ StructuredData::DictionarySP ScriptInterpreterPythonImpl::GetDynamicSettings( if (!generic) return StructuredData::DictionarySP(); - PythonObject reply_pyobj; Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); TargetSP target_sp(target->shared_from_this()); - reply_pyobj.Reset(PyRefType::Owned, - (PyObject *)LLDBSWIGPython_GetDynamicSetting( - generic->GetValue(), setting_name, target_sp)); - PythonDictionary py_dict(PyRefType::Borrowed, reply_pyobj.get()); + auto setting = (PyObject *)LLDBSWIGPython_GetDynamicSetting( + generic->GetValue(), setting_name, target_sp); + + if (!setting) + return StructuredData::DictionarySP(); + + PythonDictionary py_dict = + unwrapIgnoringErrors(As<PythonDictionary>(Take<PythonObject>(setting))); + + if (!py_dict) + return StructuredData::DictionarySP(); + return py_dict.CreateStructuredDictionary(); } @@ -2230,18 +2157,6 @@ bool ScriptInterpreterPythonImpl::GetScriptedSummary( return ret_val; } -void ScriptInterpreterPythonImpl::Clear() { - // Release any global variables that might have strong references to - // LLDB objects when clearing the python script interpreter. - Locker locker(this, Locker::AcquireLock, Locker::FreeAcquiredLock); - - // This may be called as part of Py_Finalize. In that case the modules are - // destroyed in random order and we can't guarantee that we can access these. - if (Py_IsInitialized()) - PyRun_SimpleString("lldb.debugger = None; lldb.target = None; lldb.process " - "= None; lldb.thread = None; lldb.frame = None"); -} - bool ScriptInterpreterPythonImpl::BreakpointCallbackFunction( void *baton, StoppointCallbackContext *context, user_id_t break_id, user_id_t break_loc_id) { |