diff options
Diffstat (limited to 'lldb/source/Interpreter/ScriptInterpreterPython.cpp')
-rw-r--r-- | lldb/source/Interpreter/ScriptInterpreterPython.cpp | 1520 |
1 files changed, 479 insertions, 1041 deletions
diff --git a/lldb/source/Interpreter/ScriptInterpreterPython.cpp b/lldb/source/Interpreter/ScriptInterpreterPython.cpp index fb60fedbe94..a2740cf96e1 100644 --- a/lldb/source/Interpreter/ScriptInterpreterPython.cpp +++ b/lldb/source/Interpreter/ScriptInterpreterPython.cpp @@ -27,11 +27,14 @@ #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Breakpoint/WatchpointOptions.h" +#include "lldb/Core/Communication.h" +#include "lldb/Core/ConnectionFileDescriptor.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Timer.h" #include "lldb/Host/Host.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/PythonDataObjects.h" #include "lldb/Target/Thread.h" using namespace lldb; @@ -66,22 +69,23 @@ _check_and_flush (FILE *stream) return fflush (stream) || prev_fail ? EOF : 0; } +static std::string +ReadPythonBacktrace (PyObject* py_backtrace); + ScriptInterpreterPython::Locker::Locker (ScriptInterpreterPython *py_interpreter, uint16_t on_entry, uint16_t on_leave, - FILE* wait_msg_handle) : + FILE *in, + FILE *out, + FILE *err) : ScriptInterpreterLocker (), m_teardown_session( (on_leave & TearDownSession) == TearDownSession ), - m_python_interpreter(py_interpreter), - m_tmp_fh(wait_msg_handle) + m_python_interpreter(py_interpreter) { - if (m_python_interpreter && !m_tmp_fh) - m_tmp_fh = (m_python_interpreter->m_dbg_stdout ? m_python_interpreter->m_dbg_stdout : stdout); - DoAcquireLock(); if ((on_entry & InitSession) == InitSession) { - if (DoInitSession((on_entry & InitGlobals) == InitGlobals) == false) + if (DoInitSession((on_entry & InitGlobals) == InitGlobals, in, out, err) == false) { // Don't teardown the session if we didn't init it. m_teardown_session = false; @@ -100,11 +104,11 @@ ScriptInterpreterPython::Locker::DoAcquireLock() } bool -ScriptInterpreterPython::Locker::DoInitSession(bool init_lldb_globals) +ScriptInterpreterPython::Locker::DoInitSession(bool init_lldb_globals, FILE *in, FILE *out, FILE *err) { if (!m_python_interpreter) return false; - return m_python_interpreter->EnterSession (init_lldb_globals); + return m_python_interpreter->EnterSession (init_lldb_globals, in, out, err); } bool @@ -133,268 +137,29 @@ ScriptInterpreterPython::Locker::~Locker() DoFreeLock(); } -ScriptInterpreterPython::PythonInputReaderManager::PythonInputReaderManager (ScriptInterpreterPython *interpreter) : -m_interpreter(interpreter), -m_debugger_sp(), -m_reader_sp(), -m_error(false) -{ - if (m_interpreter == NULL) - { - m_error = true; - return; - } - - m_debugger_sp = m_interpreter->GetCommandInterpreter().GetDebugger().shared_from_this(); - - if (!m_debugger_sp) - { - m_error = true; - return; - } - - m_reader_sp = InputReaderSP(new InputReader(*m_debugger_sp.get())); - - if (!m_reader_sp) - { - m_error = true; - return; - } - - Error error (m_reader_sp->Initialize (ScriptInterpreterPython::PythonInputReaderManager::InputReaderCallback, - m_interpreter, // baton - eInputReaderGranularityLine, // token size, to pass to callback function - NULL, // end token - NULL, // prompt - true)); // echo input - if (error.Fail()) - m_error = true; - else - { - m_debugger_sp->PushInputReader (m_reader_sp); - m_interpreter->m_embedded_thread_input_reader_sp = m_reader_sp; - } -} - -ScriptInterpreterPython::PythonInputReaderManager::~PythonInputReaderManager() -{ - // Nothing to do if either m_interpreter or m_reader_sp is invalid. - if (!m_interpreter || !m_reader_sp) - return; - - m_reader_sp->SetIsDone (true); - if (m_debugger_sp) - m_debugger_sp->PopInputReader(m_reader_sp); - - // Only mess with m_interpreter's counterpart if, indeed, they are the same object. - if (m_reader_sp.get() == m_interpreter->m_embedded_thread_input_reader_sp.get()) - { - m_interpreter->m_embedded_thread_pty.CloseSlaveFileDescriptor(); - m_interpreter->m_embedded_thread_input_reader_sp.reset(); - } -} - -size_t -ScriptInterpreterPython::PythonInputReaderManager::InputReaderCallback (void *baton, - InputReader &reader, - InputReaderAction notification, - const char *bytes, - size_t bytes_len) -{ - lldb::thread_t embedded_interpreter_thread; - Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT)); - - if (baton == NULL) - return 0; - - ScriptInterpreterPython *script_interpreter = (ScriptInterpreterPython *) baton; - - if (script_interpreter->m_script_lang != eScriptLanguagePython) - return 0; - - switch (notification) - { - case eInputReaderActivate: - { - // Save terminal settings if we can - int input_fd = reader.GetDebugger().GetInputFile().GetDescriptor(); - if (input_fd == File::kInvalidDescriptor) - input_fd = STDIN_FILENO; - - script_interpreter->SaveTerminalState(input_fd); - - char error_str[1024]; - if (script_interpreter->m_embedded_thread_pty.OpenFirstAvailableMaster (O_RDWR|O_NOCTTY, error_str, - sizeof(error_str))) - { - if (log) - log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, Activate, succeeded in opening master pty (fd = %d).", - script_interpreter->m_embedded_thread_pty.GetMasterFileDescriptor()); - { - StreamString run_string; - char error_str[1024]; - const char *pty_slave_name = script_interpreter->m_embedded_thread_pty.GetSlaveName (error_str, sizeof (error_str)); - if (pty_slave_name != NULL && PyThreadState_GetDict() != NULL) - { - ScriptInterpreterPython::Locker locker(script_interpreter, - ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | ScriptInterpreterPython::Locker::InitGlobals, - ScriptInterpreterPython::Locker::FreeAcquiredLock); - run_string.Printf ("run_one_line (%s, 'save_stderr = sys.stderr')", script_interpreter->m_dictionary_name.c_str()); - PyRun_SimpleString (run_string.GetData()); - run_string.Clear (); - - run_string.Printf ("run_one_line (%s, 'sys.stderr = sys.stdout')", script_interpreter->m_dictionary_name.c_str()); - PyRun_SimpleString (run_string.GetData()); - run_string.Clear (); - - run_string.Printf ("run_one_line (%s, 'save_stdin = sys.stdin')", script_interpreter->m_dictionary_name.c_str()); - PyRun_SimpleString (run_string.GetData()); - run_string.Clear (); - - run_string.Printf ("run_one_line (%s, \"sys.stdin = open ('%s', 'r')\")", script_interpreter->m_dictionary_name.c_str(), - pty_slave_name); - PyRun_SimpleString (run_string.GetData()); - run_string.Clear (); - } - } - embedded_interpreter_thread = Host::ThreadCreate ("<lldb.script-interpreter.noninteractive-python>", - ScriptInterpreterPython::PythonInputReaderManager::RunPythonInputReader, - script_interpreter, NULL); - if (IS_VALID_LLDB_HOST_THREAD(embedded_interpreter_thread)) - { - if (log) - log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, Activate, succeeded in creating thread (thread_t = %p)", (void *)embedded_interpreter_thread); - Error detach_error; - Host::ThreadDetach (embedded_interpreter_thread, &detach_error); - } - else - { - if (log) - log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, Activate, failed in creating thread"); - reader.SetIsDone (true); - } - } - else - { - if (log) - log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, Activate, failed to open master pty "); - reader.SetIsDone (true); - } - } - break; - - case eInputReaderDeactivate: - // When another input reader is pushed, don't leave the session... - //script_interpreter->LeaveSession (); - break; - - case eInputReaderReactivate: -// { -// ScriptInterpreterPython::Locker locker(script_interpreter, -// ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession, -// ScriptInterpreterPython::Locker::FreeAcquiredLock); -// } - break; - - case eInputReaderAsynchronousOutputWritten: - break; - - case eInputReaderInterrupt: - { - PyThreadState* state = _PyThreadState_Current; - if (!state) - state = script_interpreter->m_command_thread_state; - if (state) - { - long tid = state->thread_id; - _PyThreadState_Current = state; - int num_threads = PyThreadState_SetAsyncExc(tid, PyExc_KeyboardInterrupt); - if (log) - log->Printf("ScriptInterpreterPython::NonInteractiveInputReaderCallback, eInputReaderInterrupt, tid = %ld, num_threads = %d, state = %p", - tid,num_threads,state); - } - else if (log) - log->Printf("ScriptInterpreterPython::NonInteractiveInputReaderCallback, eInputReaderInterrupt, state = NULL"); - } - break; - - case eInputReaderEndOfFile: - reader.SetIsDone(true); - break; - - case eInputReaderGotToken: - if (script_interpreter->m_embedded_thread_pty.GetMasterFileDescriptor() != -1) - { - if (log) - log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, GotToken, bytes='%s', byte_len = %zu", bytes, - bytes_len); - if (bytes && bytes_len) - ::write (script_interpreter->m_embedded_thread_pty.GetMasterFileDescriptor(), bytes, bytes_len); - ::write (script_interpreter->m_embedded_thread_pty.GetMasterFileDescriptor(), "\n", 1); - } - else - { - if (log) - log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, GotToken, bytes='%s', byte_len = %zu, Master File Descriptor is bad.", - bytes, - bytes_len); - reader.SetIsDone (true); - } - break; - - case eInputReaderDone: - { - StreamString run_string; - char error_str[1024]; - const char *pty_slave_name = script_interpreter->m_embedded_thread_pty.GetSlaveName (error_str, sizeof (error_str)); - if (pty_slave_name != NULL && PyThreadState_GetDict() != NULL) - { - ScriptInterpreterPython::Locker locker(script_interpreter, - ScriptInterpreterPython::Locker::AcquireLock, - ScriptInterpreterPython::Locker::FreeAcquiredLock); - run_string.Printf ("run_one_line (%s, 'sys.stdin = save_stdin; sys.stderr = save_stderr')", script_interpreter->m_dictionary_name.c_str()); - PyRun_SimpleString (run_string.GetData()); - run_string.Clear(); - } - // Restore terminal settings if they were validly saved - if (log) - log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, Done, closing down input reader."); - - script_interpreter->RestoreTerminalState (); - - script_interpreter->m_embedded_thread_pty.CloseMasterFileDescriptor(); - } - break; - } - - return bytes_len; -} ScriptInterpreterPython::ScriptInterpreterPython (CommandInterpreter &interpreter) : ScriptInterpreter (interpreter, eScriptLanguagePython), - m_embedded_thread_pty (), - m_embedded_python_pty (), - m_embedded_thread_input_reader_sp (), - m_embedded_python_input_reader_sp (), - m_dbg_stdout (interpreter.GetDebugger().GetOutputFile().GetStream()), - m_new_sysout (NULL), - m_old_sysout (NULL), - m_old_syserr (NULL), - m_run_one_line (NULL), + IOHandlerDelegateMultiline("DONE"), + m_saved_stdin (), + m_saved_stdout (), + m_saved_stderr (), + m_main_module (), + m_lldb_module (), + m_session_dict (false), // Don't create an empty dictionary, leave it invalid + m_sys_module_dict (false), // Don't create an empty dictionary, leave it invalid + m_run_one_line_function (), + m_run_one_line_str_global (), m_dictionary_name (interpreter.GetDebugger().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_command_thread_state (NULL) { - static int g_initialized = false; - - if (!g_initialized) - { - g_initialized = true; - ScriptInterpreterPython::InitializePrivate (); - } + ScriptInterpreterPython::InitializePrivate (); m_dictionary_name.append("_dict"); StreamString run_string; @@ -435,62 +200,116 @@ ScriptInterpreterPython::ScriptInterpreterPython (CommandInterpreter &interprete run_string.Printf ("run_one_line (%s, 'lldb.debugger_unique_id = %" PRIu64 "; pydoc.pager = pydoc.plainpager')", m_dictionary_name.c_str(), interpreter.GetDebugger().GetID()); PyRun_SimpleString (run_string.GetData()); - - if (m_dbg_stdout != NULL) - { - m_new_sysout = PyFile_FromFile (m_dbg_stdout, (char *) "", (char *) "w", _check_and_flush); - } - - // get the output file handle from the debugger (if any) - File& out_file = interpreter.GetDebugger().GetOutputFile(); - if (out_file.IsValid()) - ResetOutputFileHandle(out_file.GetStream()); } ScriptInterpreterPython::~ScriptInterpreterPython () { - Debugger &debugger = GetCommandInterpreter().GetDebugger(); +} - if (m_embedded_thread_input_reader_sp.get() != NULL) - { - m_embedded_thread_input_reader_sp->SetIsDone (true); - m_embedded_thread_pty.CloseSlaveFileDescriptor(); - const InputReaderSP reader_sp = m_embedded_thread_input_reader_sp; - debugger.PopInputReader (reader_sp); - m_embedded_thread_input_reader_sp.reset(); - } +void +ScriptInterpreterPython::IOHandlerActivated (IOHandler &io_handler) +{ + const char *instructions = NULL; - if (m_embedded_python_input_reader_sp.get() != NULL) + switch (m_active_io_handler) { - m_embedded_python_input_reader_sp->SetIsDone (true); - m_embedded_python_pty.CloseSlaveFileDescriptor(); - const InputReaderSP reader_sp = m_embedded_python_input_reader_sp; - debugger.PopInputReader (reader_sp); - m_embedded_python_input_reader_sp.reset(); + case eIOHandlerNone: + break; + case eIOHandlerBreakpoint: + instructions = R"(Enter your Python command(s). Type 'DONE' to end. +def function (frame, bp_loc, internal_dict): + """frame: the lldb.SBFrame for the location at which you stopped + bp_loc: an lldb.SBBreakpointLocation for the breakpoint location information + internal_dict: an LLDB support object not to be used""" +)"; + break; + case eIOHandlerWatchpoint: + instructions = "Enter your Python command(s). Type 'DONE' to end.\n"; + break; } - if (m_new_sysout) + if (instructions) { - Locker locker(this, - ScriptInterpreterPython::Locker::AcquireLock, - ScriptInterpreterPython::Locker::FreeLock); - Py_XDECREF ((PyObject*)m_new_sysout); + StreamFileSP output_sp(io_handler.GetOutputStreamFile()); + if (output_sp) + { + output_sp->PutCString(instructions); + output_sp->Flush(); + } } } void -ScriptInterpreterPython::ResetOutputFileHandle (FILE *fh) +ScriptInterpreterPython::IOHandlerInputComplete (IOHandler &io_handler, std::string &data) { - if (fh == NULL) - return; - - m_dbg_stdout = fh; + io_handler.SetIsDone(true); + bool batch_mode = m_interpreter.GetBatchCommandMode(); + + switch (m_active_io_handler) + { + case eIOHandlerNone: + break; + case eIOHandlerBreakpoint: + { + BreakpointOptions *bp_options = (BreakpointOptions *)io_handler.GetUserData(); + std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); + if (data_ap.get()) + { + data_ap->user_source.SplitIntoLines(data); + + if (GenerateBreakpointCommandCallbackData (data_ap->user_source, data_ap->script_source)) + { + BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); + bp_options->SetCallback (ScriptInterpreterPython::BreakpointCallbackFunction, baton_sp); + } + else if (!batch_mode) + { + StreamFileSP error_sp = io_handler.GetErrorStreamFile(); + if (error_sp) + { + error_sp->Printf ("Warning: No command attached to breakpoint.\n"); + error_sp->Flush(); + } + } + } + m_active_io_handler = eIOHandlerNone; + } + break; + case eIOHandlerWatchpoint: + { + WatchpointOptions *wp_options = (WatchpointOptions *)io_handler.GetUserData(); + std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData()); + if (data_ap.get()) + { + data_ap->user_source.SplitIntoLines(data); + + if (GenerateWatchpointCommandCallbackData (data_ap->user_source, data_ap->script_source)) + { + BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release())); + wp_options->SetCallback (ScriptInterpreterPython::WatchpointCallbackFunction, baton_sp); + } + else if (!batch_mode) + { + StreamFileSP error_sp = io_handler.GetErrorStreamFile(); + if (error_sp) + { + error_sp->Printf ("Warning: No command attached to breakpoint.\n"); + error_sp->Flush(); + } + } + } + m_active_io_handler = eIOHandlerNone; + } + break; + } - Locker locker(this, - ScriptInterpreterPython::Locker::AcquireLock, - ScriptInterpreterPython::Locker::FreeAcquiredLock); - m_new_sysout = PyFile_FromFile (m_dbg_stdout, (char *) "", (char *) "w", _check_and_flush); +} + + +void +ScriptInterpreterPython::ResetOutputFileHandle (FILE *fh) +{ } void @@ -529,15 +348,15 @@ ScriptInterpreterPython::LeaveSession () // When the current thread state is NULL, PyThreadState_Get() issues a fatal error. if (PyThreadState_GetDict()) { - PyObject *sysmod = PyImport_AddModule ("sys"); - PyObject *sysdict = PyModule_GetDict (sysmod); - - if (m_new_sysout && sysmod && sysdict) + PythonDictionary &sys_module_dict = GetSysModuleDictionary (); + if (sys_module_dict) { - if (m_old_sysout) - PyDict_SetItemString (sysdict, "stdout", (PyObject*)m_old_sysout); - if (m_old_syserr) - PyDict_SetItemString (sysdict, "stderr", (PyObject*)m_old_syserr); + if (m_saved_stdin) + sys_module_dict.SetItemForKey("stdin", m_saved_stdin); + if (m_saved_stdout) + sys_module_dict.SetItemForKey("stdout", m_saved_stdout); + if (m_saved_stderr) + sys_module_dict.SetItemForKey("stderr", m_saved_stderr); } } @@ -545,7 +364,10 @@ ScriptInterpreterPython::LeaveSession () } bool -ScriptInterpreterPython::EnterSession (bool init_lldb_globals) +ScriptInterpreterPython::EnterSession (bool init_lldb_globals, + FILE *in, + FILE *out, + FILE *err) { // If we have already entered the session, without having officially 'left' it, then there is no need to // 'enter' it again. @@ -578,26 +400,53 @@ ScriptInterpreterPython::EnterSession (bool init_lldb_globals) else { // If we aren't initing the globals, we should still always set the debugger (since that is always unique.) - run_string.Printf ( "run_one_line (%s, \"lldb.debugger_unique_id = %" PRIu64, m_dictionary_name.c_str(), GetCommandInterpreter().GetDebugger().GetID()); + run_string.Printf ( "run_one_line (%s, 'lldb.debugger_unique_id = %" PRIu64, m_dictionary_name.c_str(), GetCommandInterpreter().GetDebugger().GetID()); run_string.Printf ( "; lldb.debugger = lldb.SBDebugger.FindDebuggerWithID (%" PRIu64 ")", GetCommandInterpreter().GetDebugger().GetID()); - run_string.PutCString ("\")"); + run_string.PutCString ("')"); } PyRun_SimpleString (run_string.GetData()); run_string.Clear(); - PyObject *sysmod = PyImport_AddModule ("sys"); - PyObject *sysdict = PyModule_GetDict (sysmod); - - if (m_new_sysout && sysmod && sysdict) + PythonDictionary &sys_module_dict = GetSysModuleDictionary (); + if (sys_module_dict) { - m_old_sysout = PyDict_GetItemString(sysdict, "stdout"); - m_old_syserr = PyDict_GetItemString(sysdict, "stderr"); - if (m_new_sysout) + lldb::StreamFileSP in_sp; + lldb::StreamFileSP out_sp; + lldb::StreamFileSP err_sp; + if (in == NULL || out == NULL || err == NULL) + m_interpreter.GetDebugger().AdoptTopIOHandlerFilesIfInvalid (in_sp, out_sp, err_sp); + + if (in == NULL && in_sp) + in = in_sp->GetFile().GetStream(); + if (in) { - PyDict_SetItemString (sysdict, "stdout", (PyObject*)m_new_sysout); - PyDict_SetItemString (sysdict, "stderr", (PyObject*)m_new_sysout); + m_saved_stdin.Reset(sys_module_dict.GetItemForKey("stdin")); + + sys_module_dict.SetItemForKey ("stdin", PyFile_FromFile (in, (char *) "", (char *) "r", 0)); } + else + m_saved_stdin.Reset(); + + if (out == NULL && out_sp) + out = out_sp->GetFile().GetStream(); + if (out) + { + m_saved_stdout.Reset(sys_module_dict.GetItemForKey("stdout")); + sys_module_dict.SetItemForKey ("stdout", PyFile_FromFile (out, (char *) "", (char *) "w", 0)); + } + else + m_saved_stdout.Reset(); + + if (err == NULL && err_sp) + err = err_sp->GetFile().GetStream(); + if (err) + { + m_saved_stderr.Reset(sys_module_dict.GetItemForKey("stderr")); + sys_module_dict.SetItemForKey ("stderr", PyFile_FromFile (err, (char *) "", (char *) "w", 0)); + } + else + m_saved_stdout.Reset(); } if (PyErr_Occurred()) @@ -606,44 +455,42 @@ ScriptInterpreterPython::EnterSession (bool init_lldb_globals) return true; } -static PyObject* -FindSessionDictionary (const char* dict_name) +PythonObject & +ScriptInterpreterPython::GetMainModule () { - static std::map<ConstString,PyObject*> g_dict_map; - - ConstString dict(dict_name); - - std::map<ConstString,PyObject*>::iterator iter = g_dict_map.find(dict); - - if (iter != g_dict_map.end()) - return iter->second; - - PyObject *main_mod = PyImport_AddModule ("__main__"); - if (main_mod != NULL) + if (!m_main_module) + m_main_module.Reset(PyImport_AddModule ("__main__")); + return m_main_module; +} + +PythonDictionary & +ScriptInterpreterPython::GetSessionDictionary () +{ + if (!m_session_dict) { - PyObject *main_dict = PyModule_GetDict (main_mod); - if ((main_dict != NULL) - && PyDict_Check (main_dict)) + PythonObject &main_module = GetMainModule (); + if (main_module) { - // Go through the main dictionary looking for the correct python script interpreter dictionary - PyObject *key, *value; - Py_ssize_t pos = 0; - - while (PyDict_Next (main_dict, &pos, &key, &value)) + PythonDictionary main_dict(PyModule_GetDict (main_module.get())); + if (main_dict) { - // We have stolen references to the key and value objects in the dictionary; we need to increment - // them now so that Python's garbage collector doesn't collect them out from under us. - Py_INCREF (key); - Py_INCREF (value); - if (strcmp (PyString_AsString (key), dict_name) == 0) - { - g_dict_map[dict] = value; - return value; - } + m_session_dict = main_dict.GetItemForKey(m_dictionary_name.c_str()); } } } - return NULL; + return m_session_dict; +} + +PythonDictionary & +ScriptInterpreterPython::GetSysModuleDictionary () +{ + if (!m_sys_module_dict) + { + PyObject *sys_module = PyImport_AddModule ("sys"); + if (sys_module) + m_sys_module_dict.Reset(PyModule_GetDict (sys_module)); + } + return m_sys_module_dict; } static std::string @@ -665,82 +512,158 @@ GenerateUniqueName (const char* base_name_wanted, } bool +ScriptInterpreterPython::GetEmbeddedInterpreterModuleObjects () +{ + if (!m_run_one_line_function) + { + PyObject *module = PyImport_AddModule ("lldb.embedded_interpreter"); + if (module != NULL) + { + PythonDictionary module_dict (PyModule_GetDict (module)); + if (module_dict) + { + m_run_one_line_function = module_dict.GetItemForKey("run_one_line"); + m_run_one_line_str_global = module_dict.GetItemForKey("g_run_one_line_str"); + } + } + } + return (bool)m_run_one_line_function; +} + +static void +ReadThreadBytesReceived(void *baton, const void *src, size_t src_len) +{ + if (src && src_len) + { + Stream *strm = (Stream *)baton; + strm->Write(src, src_len); + strm->Flush(); + } +} + +bool ScriptInterpreterPython::ExecuteOneLine (const char *command, CommandReturnObject *result, const ExecuteScriptOptions &options) { if (!m_valid_session) return false; + + if (command && command[0]) + { + // We want to call run_one_line, passing in the dictionary and the command string. We cannot do this through + // PyRun_SimpleString here because the command string may contain escaped characters, and putting it inside + // another string to pass to PyRun_SimpleString messes up the escaping. So we use the following more complicated + // method to pass the command string directly down to Python. + Debugger &debugger = m_interpreter.GetDebugger(); - // We want to call run_one_line, passing in the dictionary and the command string. We cannot do this through - // PyRun_SimpleString here because the command string may contain escaped characters, and putting it inside - // another string to pass to PyRun_SimpleString messes up the escaping. So we use the following more complicated - // method to pass the command string directly down to Python. - - Locker locker(this, - ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0), - ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession); - - bool success = false; + StreamFileSP input_file_sp; + StreamFileSP output_file_sp; + StreamFileSP error_file_sp; + Communication output_comm ("lldb.ScriptInterpreterPython.ExecuteOneLine.comm"); + int pipe_fds[2] = { -1, -1 }; + + if (options.GetEnableIO()) + { + if (result) + { + input_file_sp = debugger.GetInputFile(); + // Set output to a temporary file so we can forward the results on to the result object + + int err = pipe(pipe_fds); + if (err == 0) + { + std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor(pipe_fds[0], false)); + if (conn_ap->IsConnected()) + { + output_comm.SetConnection(conn_ap.release()); + output_comm.SetReadThreadBytesReceivedCallback(ReadThreadBytesReceived, &result->GetOutputStream()); + output_comm.StartReadThread(); + FILE *outfile_handle = fdopen (pipe_fds[1], "w"); + output_file_sp.reset(new StreamFile(outfile_handle, true)); + error_file_sp = output_file_sp; + if (outfile_handle) + ::setbuf (outfile_handle, NULL); + + result->SetImmediateOutputFile(debugger.GetOutputFile()->GetFile().GetStream()); + result->SetImmediateErrorFile(debugger.GetErrorFile()->GetFile().GetStream()); + } + } + } + if (!input_file_sp || !output_file_sp || !error_file_sp) + debugger.AdoptTopIOHandlerFilesIfInvalid(input_file_sp, output_file_sp, error_file_sp); + } + else + { + input_file_sp.reset (new StreamFile ()); + input_file_sp->GetFile().Open("/dev/null", File::eOpenOptionRead); + output_file_sp.reset (new StreamFile ()); + output_file_sp->GetFile().Open("/dev/null", File::eOpenOptionWrite); + error_file_sp = output_file_sp; + } - if (command) - { + FILE *in_file = input_file_sp->GetFile().GetStream(); + FILE *out_file = output_file_sp->GetFile().GetStream(); + FILE *err_file = error_file_sp->GetFile().GetStream(); + Locker locker(this, + ScriptInterpreterPython::Locker::AcquireLock | + ScriptInterpreterPython::Locker::InitSession | + (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0), + ScriptInterpreterPython::Locker::FreeAcquiredLock | + ScriptInterpreterPython::Locker::TearDownSession, + in_file, + out_file, + err_file); + + bool success = false; + // Find the correct script interpreter dictionary in the main module. - PyObject *script_interpreter_dict = FindSessionDictionary(m_dictionary_name.c_str()); - if (script_interpreter_dict != NULL) + PythonDictionary &session_dict = GetSessionDictionary (); + if (session_dict) { - PyObject *pfunc = (PyObject*)m_run_one_line; - PyObject *pmod = PyImport_AddModule ("lldb.embedded_interpreter"); - if (pmod != NULL) + if (GetEmbeddedInterpreterModuleObjects ()) { - PyObject *pmod_dict = PyModule_GetDict (pmod); - if ((pmod_dict != NULL) - && PyDict_Check (pmod_dict)) + PyObject *pfunc = m_run_one_line_function.get(); + + if (pfunc && PyCallable_Check (pfunc)) { - if (!pfunc) + PythonObject pargs (Py_BuildValue("(Os)", session_dict.get(), command)); + if (pargs) { - PyObject *key, *value; - Py_ssize_t pos = 0; - - while (PyDict_Next (pmod_dict, &pos, &key, &value)) + PythonObject return_value; + { // scope for PythonInputReaderManager + //PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL); + return_value.Reset(PyObject_CallObject (pfunc, pargs.get())); + } + if (return_value) { - Py_INCREF (key); - Py_INCREF (value); - if (strcmp (PyString_AsString (key), "run_one_line") == 0) - { - pfunc = value; - break; - } + success = true; } - m_run_one_line = pfunc; - } - - if (pfunc && PyCallable_Check (pfunc)) - { - PyObject *pargs = Py_BuildValue("(Os)",script_interpreter_dict,command); - if (pargs != NULL) + else if (options.GetMaskoutErrors() && PyErr_Occurred ()) { - PyObject *pvalue = NULL; - { // scope for PythonInputReaderManager - PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL); - pvalue = PyObject_CallObject (pfunc, pargs); - } - Py_XDECREF (pargs); - if (pvalue != NULL) - { - Py_XDECREF (pvalue); - success = true; - } - else if (options.GetMaskoutErrors() && PyErr_Occurred ()) - { - PyErr_Print(); - PyErr_Clear(); - } + PyErr_Print(); + PyErr_Clear(); } } } } - Py_INCREF (script_interpreter_dict); } + // Flush our output and error file handles + ::fflush (out_file); + if (out_file != err_file) + ::fflush (err_file); + + if (pipe_fds[0] != -1) + { + // Close write end of pipe so our communication thread exits + output_comm.Disconnect(); + output_comm.StopReadThread(); + // Close the read end of the pipe and don't close the write end + // since we called fdopen on it and gave the ownership to the + // connection in "output_comm" + ::close (pipe_fds[0]); + } + + if (success) return true; @@ -755,155 +678,107 @@ ScriptInterpreterPython::ExecuteOneLine (const char *command, CommandReturnObjec return false; } -size_t -ScriptInterpreterPython::InputReaderCallback -( - void *baton, - InputReader &reader, - InputReaderAction notification, - const char *bytes, - size_t bytes_len -) -{ - lldb::thread_t embedded_interpreter_thread; - Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT)); - if (baton == NULL) - return 0; +class IOHandlerPythonInterpreter : + public IOHandler +{ +public: + + IOHandlerPythonInterpreter (Debugger &debugger, + ScriptInterpreterPython *python) : + IOHandler (debugger), + m_python(python) + { - ScriptInterpreterPython *script_interpreter = (ScriptInterpreterPython *) baton; + } - if (script_interpreter->m_script_lang != eScriptLanguagePython) - return 0; + virtual + ~IOHandlerPythonInterpreter() + { + + } - switch (notification) + virtual ConstString + GetControlSequence (char ch) { - case eInputReaderActivate: - { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); - if (!batch_mode) - { - out_stream->Printf ("Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.\n"); - out_stream->Flush(); - } - - // Save terminal settings if we can - int input_fd = reader.GetDebugger().GetInputFile().GetDescriptor(); - if (input_fd == File::kInvalidDescriptor) - input_fd = STDIN_FILENO; - - script_interpreter->SaveTerminalState(input_fd); - - { - ScriptInterpreterPython::Locker locker(script_interpreter, - ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | ScriptInterpreterPython::Locker::InitGlobals, - ScriptInterpreterPython::Locker::FreeAcquiredLock); - } + if (ch == 'd') + return ConstString("quit()\n"); + return ConstString(); + } - char error_str[1024]; - if (script_interpreter->m_embedded_python_pty.OpenFirstAvailableMaster (O_RDWR|O_NOCTTY, error_str, - sizeof(error_str))) + virtual void + Run () + { + if (m_python) + { + int stdin_fd = GetInputFD(); + if (stdin_fd >= 0) { - if (log) - log->Printf ("ScriptInterpreterPython::InputReaderCallback, Activate, succeeded in opening master pty (fd = %d).", - script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor()); - embedded_interpreter_thread = Host::ThreadCreate ("<lldb.script-interpreter.embedded-python-loop>", - ScriptInterpreterPython::RunEmbeddedPythonInterpreter, - script_interpreter, NULL); - if (IS_VALID_LLDB_HOST_THREAD(embedded_interpreter_thread)) - { - if (log) - log->Printf ("ScriptInterpreterPython::InputReaderCallback, Activate, succeeded in creating thread (thread_t = %p)", (void *)embedded_interpreter_thread); - Error detach_error; - Host::ThreadDetach (embedded_interpreter_thread, &detach_error); - } - else + Terminal terminal(stdin_fd); + TerminalState terminal_state; + const bool is_a_tty = terminal.IsATerminal(); + + if (is_a_tty) { - if (log) - log->Printf ("ScriptInterpreterPython::InputReaderCallback, Activate, failed in creating thread"); - reader.SetIsDone (true); + terminal_state.Save (stdin_fd, false); + terminal.SetCanonical(false); + terminal.SetEcho(true); } - } - else - { - if (log) - log->Printf ("ScriptInterpreterPython::InputReaderCallback, Activate, failed to open master pty "); - reader.SetIsDone (true); + + ScriptInterpreterPython::Locker locker (m_python, + ScriptInterpreterPython::Locker::AcquireLock | + ScriptInterpreterPython::Locker::InitSession | + ScriptInterpreterPython::Locker::InitGlobals, + ScriptInterpreterPython::Locker::FreeAcquiredLock | + ScriptInterpreterPython::Locker::TearDownSession); + + // The following call drops into the embedded interpreter loop and stays there until the + // user chooses to exit from the Python interpreter. + // This embedded interpreter will, as any Python code that performs I/O, unlock the GIL before + // a system call that can hang, and lock it when the syscall has returned. + + // We need to surround the call to the embedded interpreter with calls to PyGILState_Ensure and + // PyGILState_Release (using the Locker above). This is because Python has a global lock which must be held whenever we want + // to touch any Python objects. Otherwise, if the user calls Python code, the interpreter state will be off, + // and things could hang (it's happened before). + + StreamString run_string; + run_string.Printf ("run_python_interpreter (%s)", m_python->GetDictionaryName ()); + PyRun_SimpleString (run_string.GetData()); + + if (is_a_tty) + terminal_state.Restore(); } } - break; - - case eInputReaderDeactivate: - // When another input reader is pushed, don't leave the session... - //script_interpreter->LeaveSession (); - break; + SetIsDone(true); + } - case eInputReaderReactivate: - { - ScriptInterpreterPython::Locker locker (script_interpreter, - ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession, - ScriptInterpreterPython::Locker::FreeAcquiredLock); - } - break; + virtual void + Hide () + { - case eInputReaderAsynchronousOutputWritten: - break; + } + + virtual void + Refresh () + { - case eInputReaderInterrupt: - ::write (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor(), "raise KeyboardInterrupt\n", 24); - break; + } + + virtual void + Interrupt () + { - case eInputReaderEndOfFile: - ::write (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor(), "quit()\n", 7); - break; - - case eInputReaderGotToken: - if (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor() != -1) - { - if (log) - log->Printf ("ScriptInterpreterPython::InputReaderCallback, GotToken, bytes='%s', byte_len = %zu", bytes, - bytes_len); - if (bytes && bytes_len) - { - if ((int) bytes[0] == 4) - ::write (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor(), "quit()", 6); - else - ::write (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor(), bytes, bytes_len); - } - ::write (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor(), "\n", 1); - } - else - { - if (log) - log->Printf ("ScriptInterpreterPython::InputReaderCallback, GotToken, bytes='%s', byte_len = %zu, Master File Descriptor is bad.", - bytes, - bytes_len); - reader.SetIsDone (true); - } - - break; + } + + virtual void + GotEOF() + { - case eInputReaderDone: - { - Locker locker(script_interpreter, - ScriptInterpreterPython::Locker::AcquireLock, - ScriptInterpreterPython::Locker::FreeAcquiredLock); - script_interpreter->LeaveSession (); - } - - // Restore terminal settings if they were validly saved - if (log) - log->Printf ("ScriptInterpreterPython::InputReaderCallback, Done, closing down input reader."); - - script_interpreter->RestoreTerminalState (); - - script_interpreter->m_embedded_python_pty.CloseMasterFileDescriptor(); - break; } - - return bytes_len; -} +protected: + ScriptInterpreterPython *m_python; +}; void @@ -918,24 +793,13 @@ ScriptInterpreterPython::ExecuteInterpreterLoop () // try to embed a running interpreter loop inside the already running Python interpreter loop, so we won't // do it. - if (!debugger.GetInputFile().IsValid()) + if (!debugger.GetInputFile()->GetFile().IsValid()) return; - InputReaderSP reader_sp (new InputReader(debugger)); - if (reader_sp) - { - Error error (reader_sp->Initialize (ScriptInterpreterPython::InputReaderCallback, - this, // baton - eInputReaderGranularityLine, // token size, to pass to callback function - NULL, // end token - NULL, // prompt - true)); // echo input - - if (error.Success()) - { - debugger.PushInputReader (reader_sp); - m_embedded_python_input_reader_sp = reader_sp; - } + IOHandlerSP io_handler_sp (new IOHandlerPythonInterpreter (debugger, this)); + if (io_handler_sp) + { + debugger.PushIOHandler(io_handler_sp); } } @@ -951,27 +815,21 @@ ScriptInterpreterPython::ExecuteOneLineWithReturn (const char *in_string, ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession); PyObject *py_return = NULL; - PyObject *mainmod = PyImport_AddModule ("__main__"); - PyObject *globals = PyModule_GetDict (mainmod); - PyObject *locals = NULL; + PythonObject &main_module = GetMainModule (); + PythonDictionary globals (PyModule_GetDict(main_module.get())); PyObject *py_error = NULL; bool ret_success = false; - bool should_decrement_locals = false; int success; - locals = FindSessionDictionary(m_dictionary_name.c_str()); + PythonDictionary locals = GetSessionDictionary (); - if (locals == NULL) + if (!locals) { - locals = PyObject_GetAttrString (globals, m_dictionary_name.c_str()); - should_decrement_locals = true; + locals = PyObject_GetAttrString (globals.get(), m_dictionary_name.c_str()); } - if (locals == NULL) - { + if (!locals) locals = globals; - should_decrement_locals = false; - } py_error = PyErr_Occurred(); if (py_error != NULL) @@ -980,22 +838,18 @@ ScriptInterpreterPython::ExecuteOneLineWithReturn (const char *in_string, if (in_string != NULL) { { // scope for PythonInputReaderManager - PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL); - py_return = PyRun_String (in_string, Py_eval_input, globals, locals); + //PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL); + py_return = PyRun_String (in_string, Py_eval_input, globals.get(), locals.get()); if (py_return == NULL) { py_error = PyErr_Occurred (); if (py_error != NULL) PyErr_Clear (); - py_return = PyRun_String (in_string, Py_single_input, globals, locals); + py_return = PyRun_String (in_string, Py_single_input, globals.get(), locals.get()); } } - if (locals != NULL - && should_decrement_locals) - Py_XDECREF (locals); - if (py_return != NULL) { switch (return_type) @@ -1115,35 +969,31 @@ ScriptInterpreterPython::ExecuteOneLineWithReturn (const char *in_string, return ret_success; } -bool +Error ScriptInterpreterPython::ExecuteMultipleLines (const char *in_string, const ExecuteScriptOptions &options) { - + Error error; Locker locker(this, ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0), ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession); bool success = false; - PyObject *py_return = NULL; - PyObject *mainmod = PyImport_AddModule ("__main__"); - PyObject *globals = PyModule_GetDict (mainmod); - PyObject *locals = NULL; + PythonObject return_value; + PythonObject &main_module = GetMainModule (); + PythonDictionary globals (PyModule_GetDict(main_module.get())); PyObject *py_error = NULL; - bool should_decrement_locals = false; - locals = FindSessionDictionary(m_dictionary_name.c_str()); + PythonDictionary locals = GetSessionDictionary (); - if (locals == NULL) + if (!locals) { - locals = PyObject_GetAttrString (globals, m_dictionary_name.c_str()); - should_decrement_locals = true; + locals = PyObject_GetAttrString (globals.get(), m_dictionary_name.c_str()); } - if (locals == NULL) + if (!locals) { locals = globals; - should_decrement_locals = false; } py_error = PyErr_Occurred(); @@ -1159,16 +1009,11 @@ ScriptInterpreterPython::ExecuteMultipleLines (const char *in_string, const Exec if (compiled_code) { { // scope for PythonInputReaderManager - PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL); - py_return = PyEval_EvalCode (compiled_code, globals, locals); + //PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL); + return_value.Reset(PyEval_EvalCode (compiled_code, globals.get(), locals.get())); } - if (py_return != NULL) - { + if (return_value) success = true; - Py_XDECREF (py_return); - } - if (locals && should_decrement_locals) - Py_XDECREF (locals); } } } @@ -1176,324 +1021,50 @@ ScriptInterpreterPython::ExecuteMultipleLines (const char *in_string, const Exec py_error = PyErr_Occurred (); if (py_error != NULL) { - success = false; - if (options.GetMaskoutErrors()) - { - if (PyErr_GivenExceptionMatches (py_error, PyExc_SyntaxError)) - PyErr_Print (); - PyErr_Clear(); - } - } - - return success; -} - -static const char *g_reader_instructions = "Enter your Python command(s). Type 'DONE' to end."; - -static const char *g_bkpt_command_reader_instructions = "Enter your Python command(s). Type 'DONE' to end.\n" - "def function(frame,bp_loc,internal_dict):\n" - " \"\"\"frame: the SBFrame for the location at which you stopped\n" - " bp_loc: an SBBreakpointLocation for the breakpoint location information\n" - " internal_dict: an LLDB support object not to be used\"\"\""; - -size_t -ScriptInterpreterPython::GenerateBreakpointOptionsCommandCallback -( - void *baton, - InputReader &reader, - InputReaderAction notification, - const char *bytes, - size_t bytes_len -) -{ - static StringList commands_in_progress; - - switch (notification) - { - case eInputReaderActivate: - { - - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); - commands_in_progress.Clear(); - if (!batch_mode) - { - out_stream->Printf ("%s\n", g_bkpt_command_reader_instructions); - if (reader.GetPrompt()) - out_stream->Printf ("%s", reader.GetPrompt()); - out_stream->Flush (); - } - } - break; - - case eInputReaderDeactivate: - break; - - case eInputReaderReactivate: - { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); - if (reader.GetPrompt() && !batch_mode) - { - out_stream->Printf ("%s", reader.GetPrompt()); - out_stream->Flush (); - } - } - break; - - case eInputReaderAsynchronousOutputWritten: - break; +// puts(in_string); +// _PyObject_Dump (py_error); +// PyErr_Print(); +// success = false; - case eInputReaderGotToken: - { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); - std::string temp_string (bytes, bytes_len); - commands_in_progress.AppendString (temp_string.c_str()); - if (!reader.IsDone() && reader.GetPrompt() && !batch_mode) - { - out_stream->Printf ("%s", reader.GetPrompt()); - out_stream->Flush (); - } - } - break; - - case eInputReaderEndOfFile: - case eInputReaderInterrupt: - // Control-c (SIGINT) & control-d both mean finish & exit. - reader.SetIsDone(true); + PyObject *type = NULL; + PyObject *value = NULL; + PyObject *traceback = NULL; + PyErr_Fetch (&type,&value,&traceback); - // Control-c (SIGINT) ALSO means cancel; do NOT create a breakpoint command. - if (notification == eInputReaderInterrupt) - commands_in_progress.Clear(); + // get the backtrace + std::string bt = ReadPythonBacktrace(traceback); - // Fall through here... - - case eInputReaderDone: + if (value && value != Py_None) + error.SetErrorStringWithFormat("%s\n%s", PyString_AsString(PyObject_Str(value)),bt.c_str()); + else + error.SetErrorStringWithFormat("%s",bt.c_str()); + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(traceback); + if (options.GetMaskoutErrors()) { - bool batch_mode = notification == eInputReaderDone ? - reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode() : - true; - BreakpointOptions *bp_options = (BreakpointOptions *)baton; - std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); - data_ap->user_source.AppendList (commands_in_progress); - if (data_ap.get()) - { - ScriptInterpreter *interpreter = reader.GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); - if (interpreter) - { - if (interpreter->GenerateBreakpointCommandCallbackData (data_ap->user_source, - data_ap->script_source)) - { - BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); - bp_options->SetCallback (ScriptInterpreterPython::BreakpointCallbackFunction, baton_sp); - } - else if (!batch_mode) - { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - out_stream->Printf ("Warning: No command attached to breakpoint.\n"); - out_stream->Flush(); - } - } - else - { - if (!batch_mode) - { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - out_stream->Printf ("Warning: Unable to find script intepreter; no command attached to breakpoint.\n"); - out_stream->Flush(); - } - } - } + PyErr_Clear(); } - break; - } - return bytes_len; + return error; } -size_t -ScriptInterpreterPython::GenerateWatchpointOptionsCommandCallback -( - void *baton, - InputReader &reader, - InputReaderAction notification, - const char *bytes, - size_t bytes_len -) -{ - static StringList commands_in_progress; - - switch (notification) - { - case eInputReaderActivate: - { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); - - commands_in_progress.Clear(); - if (!batch_mode) - { - out_stream->Printf ("%s\n", g_reader_instructions); - if (reader.GetPrompt()) - out_stream->Printf ("%s", reader.GetPrompt()); - out_stream->Flush (); - } - } - break; - - case eInputReaderDeactivate: - break; - - case eInputReaderReactivate: - { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); - if (reader.GetPrompt() && !batch_mode) - { - out_stream->Printf ("%s", reader.GetPrompt()); - out_stream->Flush (); - } - } - break; - - case eInputReaderAsynchronousOutputWritten: - break; - - case eInputReaderGotToken: - { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); - std::string temp_string (bytes, bytes_len); - commands_in_progress.AppendString (temp_string.c_str()); - if (!reader.IsDone() && reader.GetPrompt() && !batch_mode) - { - out_stream->Printf ("%s", reader.GetPrompt()); - out_stream->Flush (); - } - } - break; - - case eInputReaderEndOfFile: - case eInputReaderInterrupt: - // Control-c (SIGINT) & control-d both mean finish & exit. - reader.SetIsDone(true); - - // Control-c (SIGINT) ALSO means cancel; do NOT create a breakpoint command. - if (notification == eInputReaderInterrupt) - commands_in_progress.Clear(); - - // Fall through here... - - case eInputReaderDone: - { - bool batch_mode = notification == eInputReaderDone ? - reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode() : - true; - WatchpointOptions *wp_options = (WatchpointOptions *)baton; - std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData()); - data_ap->user_source.AppendList (commands_in_progress); - if (data_ap.get()) - { - ScriptInterpreter *interpreter = reader.GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); - if (interpreter) - { - if (interpreter->GenerateWatchpointCommandCallbackData (data_ap->user_source, - data_ap->script_source)) - { - BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release())); - wp_options->SetCallback (ScriptInterpreterPython::WatchpointCallbackFunction, baton_sp); - } - else if (!batch_mode) - { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - out_stream->Printf ("Warning: No command attached to breakpoint.\n"); - out_stream->Flush(); - } - } - else - { - if (!batch_mode) - { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - out_stream->Printf ("Warning: Unable to find script intepreter; no command attached to breakpoint.\n"); - out_stream->Flush(); - } - } - } - } - break; - - } - - return bytes_len; -} void ScriptInterpreterPython::CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options, CommandReturnObject &result) { - Debugger &debugger = GetCommandInterpreter().GetDebugger(); - - InputReaderSP reader_sp (new InputReader (debugger)); - - if (reader_sp) - { - Error err = reader_sp->Initialize ( - ScriptInterpreterPython::GenerateBreakpointOptionsCommandCallback, - bp_options, // baton - eInputReaderGranularityLine, // token size, for feeding data to callback function - "DONE", // end token - " ", // prompt - true); // echo input - - if (err.Success()) - debugger.PushInputReader (reader_sp); - else - { - result.AppendError (err.AsCString()); - result.SetStatus (eReturnStatusFailed); - } - } - else - { - result.AppendError("out of memory"); - result.SetStatus (eReturnStatusFailed); - } + m_active_io_handler = eIOHandlerBreakpoint; + m_interpreter.GetPythonCommandsFromIOHandler (" ", *this, true, bp_options); } void ScriptInterpreterPython::CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options, CommandReturnObject &result) { - Debugger &debugger = GetCommandInterpreter().GetDebugger(); - - InputReaderSP reader_sp (new InputReader (debugger)); - - if (reader_sp) - { - Error err = reader_sp->Initialize ( - ScriptInterpreterPython::GenerateWatchpointOptionsCommandCallback, - wp_options, // baton - eInputReaderGranularityLine, // token size, for feeding data to callback function - "DONE", // end token - "> ", // prompt - true); // echo input - - if (err.Success()) - debugger.PushInputReader (reader_sp); - else - { - result.AppendError (err.AsCString()); - result.SetStatus (eReturnStatusFailed); - } - } - else - { - result.AppendError("out of memory"); - result.SetStatus (eReturnStatusFailed); - } + m_active_io_handler = eIOHandlerWatchpoint; + m_interpreter.GetPythonCommandsFromIOHandler (" ", *this, true, wp_options); } // Set a Python one-liner as the callback for the breakpoint. @@ -1548,7 +1119,7 @@ ScriptInterpreterPython::ExportFunctionDefinitionToInterpreter (StringList &func // Convert StringList to one long, newline delimited, const char *. std::string function_def_string(function_def.CopyList()); - return ExecuteMultipleLines (function_def_string.c_str(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false)); + return ExecuteMultipleLines (function_def_string.c_str(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false)).Success(); } bool @@ -2140,7 +1711,7 @@ ScriptInterpreterPython::GetScriptedSummary (const char *python_function_name, { Timer scoped_timer ("g_swig_typescript_callback","g_swig_typescript_callback"); ret_val = g_swig_typescript_callback (python_function_name, - FindSessionDictionary(m_dictionary_name.c_str()), + GetSessionDictionary().get(), valobj, &new_callee, retval); @@ -2188,8 +1759,7 @@ ScriptInterpreterPython::BreakpointCallbackFunction if (!script_interpreter) return true; - if (python_function_name != NULL - && python_function_name[0] != '\0') + if (python_function_name && python_function_name[0]) { const StackFrameSP stop_frame_sp (exe_ctx.GetFrameSP()); BreakpointSP breakpoint_sp = target->GetBreakpointByID (break_id); @@ -2243,8 +1813,7 @@ ScriptInterpreterPython::WatchpointCallbackFunction if (!script_interpreter) return true; - if (python_function_name != NULL - && python_function_name[0] != '\0') + if (python_function_name && python_function_name[0]) { const StackFrameSP stop_frame_sp (exe_ctx.GetFrameSP()); WatchpointSP wp_sp = target->GetWatchpointList().FindByID (watch_id); @@ -2269,106 +1838,6 @@ ScriptInterpreterPython::WatchpointCallbackFunction return true; } -lldb::thread_result_t -ScriptInterpreterPython::RunEmbeddedPythonInterpreter (lldb::thread_arg_t baton) -{ - ScriptInterpreterPython *script_interpreter = (ScriptInterpreterPython *) baton; - - Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT)); - - if (log) - log->Printf ("%p ScriptInterpreterPython::RunEmbeddedPythonInterpreter () thread starting...", baton); - - char error_str[1024]; - const char *pty_slave_name = script_interpreter->m_embedded_python_pty.GetSlaveName (error_str, sizeof (error_str)); - - if (pty_slave_name != NULL) - { - StreamString run_string; - - // Ensure we have the GIL before running any Python code. - // Since we're only running a few one-liners and then dropping to the interpreter (which will release the GIL when needed), - // we can just release the GIL after finishing our work. - // If finer-grained locking is desirable, we can lock and unlock the GIL only when calling a python function. - Locker locker(script_interpreter, - ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | ScriptInterpreterPython::Locker::InitGlobals, - ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession); - - run_string.Printf ("run_one_line (%s, 'save_stderr = sys.stderr')", script_interpreter->m_dictionary_name.c_str()); - PyRun_SimpleString (run_string.GetData()); - run_string.Clear (); - - run_string.Printf ("run_one_line (%s, 'sys.stderr = sys.stdout')", script_interpreter->m_dictionary_name.c_str()); - PyRun_SimpleString (run_string.GetData()); - run_string.Clear (); - - run_string.Printf ("run_one_line (%s, 'save_stdin = sys.stdin')", script_interpreter->m_dictionary_name.c_str()); - PyRun_SimpleString (run_string.GetData()); - run_string.Clear (); - - run_string.Printf ("run_one_line (%s, \"sys.stdin = open ('%s', 'r')\")", script_interpreter->m_dictionary_name.c_str(), - pty_slave_name); - PyRun_SimpleString (run_string.GetData()); - run_string.Clear (); - - // The following call drops into the embedded interpreter loop and stays there until the - // user chooses to exit from the Python interpreter. - // This embedded interpreter will, as any Python code that performs I/O, unlock the GIL before - // a system call that can hang, and lock it when the syscall has returned. - - // We need to surround the call to the embedded interpreter with calls to PyGILState_Ensure and - // PyGILState_Release (using the Locker above). This is because Python has a global lock which must be held whenever we want - // to touch any Python objects. Otherwise, if the user calls Python code, the interpreter state will be off, - // and things could hang (it's happened before). - - run_string.Printf ("run_python_interpreter (%s)", script_interpreter->m_dictionary_name.c_str()); - PyRun_SimpleString (run_string.GetData()); - run_string.Clear (); - - run_string.Printf ("run_one_line (%s, 'sys.stdin = save_stdin')", script_interpreter->m_dictionary_name.c_str()); - PyRun_SimpleString (run_string.GetData()); - run_string.Clear(); - - run_string.Printf ("run_one_line (%s, 'sys.stderr = save_stderr')", script_interpreter->m_dictionary_name.c_str()); - PyRun_SimpleString (run_string.GetData()); - run_string.Clear(); - } - - if (script_interpreter->m_embedded_python_input_reader_sp) - script_interpreter->m_embedded_python_input_reader_sp->SetIsDone (true); - - script_interpreter->m_embedded_python_pty.CloseSlaveFileDescriptor(); - - log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT); - if (log) - log->Printf ("%p ScriptInterpreterPython::RunEmbeddedPythonInterpreter () thread exiting...", baton); - - - // Clean up the input reader and make the debugger pop it off the stack. - Debugger &debugger = script_interpreter->GetCommandInterpreter().GetDebugger(); - const InputReaderSP reader_sp = script_interpreter->m_embedded_python_input_reader_sp; - if (reader_sp) - { - debugger.PopInputReader (reader_sp); - script_interpreter->m_embedded_python_input_reader_sp.reset(); - } - - return NULL; -} - -lldb::thread_result_t -ScriptInterpreterPython::PythonInputReaderManager::RunPythonInputReader (lldb::thread_arg_t baton) -{ - ScriptInterpreterPython *script_interpreter = (ScriptInterpreterPython *) baton; - - const InputReaderSP reader_sp = script_interpreter->m_embedded_thread_input_reader_sp; - - if (reader_sp) - reader_sp->WaitOnReaderIsDone(); - - return NULL; -} - size_t ScriptInterpreterPython::CalculateNumChildren (const lldb::ScriptInterpreterObjectSP& implementor_sp) { @@ -2755,7 +2224,7 @@ ScriptInterpreterPython::LoadScriptingModule (const char* pathname, command_stream.Printf("if not (sys.path.__contains__('%s')):\n sys.path.insert(1,'%s');\n\n", directory.c_str(), directory.c_str()); - bool syspath_retval = ExecuteMultipleLines(command_stream.GetData(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false).SetSetLLDBGlobals(false)); + bool syspath_retval = ExecuteMultipleLines(command_stream.GetData(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false).SetSetLLDBGlobals(false)).Success(); if (!syspath_retval) { error.SetErrorString("Python sys.path handling failed"); @@ -2818,47 +2287,9 @@ ScriptInterpreterPython::LoadScriptingModule (const char* pathname, else command_stream.Printf("import %s",basename.c_str()); - bool import_retval = ExecuteMultipleLines(command_stream.GetData(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false).SetSetLLDBGlobals(false).SetMaskoutErrors(false)); - PyObject* py_error = PyErr_Occurred(); // per Python docs: "you do not need to Py_DECREF()" the return of this function - - if (py_error || !import_retval) // check for failure of the import - { - if (py_error) // if we have a Python error.. - { - PyObject *type = NULL,*value = NULL,*traceback = NULL; - PyErr_Fetch (&type,&value,&traceback); - - if (PyErr_GivenExceptionMatches (py_error, PyExc_ImportError)) // and it is an ImportError - { - if (value && value != Py_None) - error.SetErrorString(PyString_AsString(PyObject_Str(value))); - else - error.SetErrorString("ImportError raised by imported module"); - } - else // any other error - { - // get the backtrace - std::string bt = ReadPythonBacktrace(traceback); - - if (value && value != Py_None) - error.SetErrorStringWithFormat("Python error raised while importing module: %s - traceback: %s", PyString_AsString(PyObject_Str(value)),bt.c_str()); - else - error.SetErrorStringWithFormat("Python raised an error while importing module - traceback: %s",bt.c_str()); - } - - Py_XDECREF(type); - Py_XDECREF(value); - Py_XDECREF(traceback); - } - else // we failed but have no error to explain why - { - error.SetErrorString("unknown error while importing module"); - } - - // anyway, clear the error indicator and return false - PyErr_Clear(); + error = ExecuteMultipleLines(command_stream.GetData(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false).SetSetLLDBGlobals(false)); + if (error.Fail()) return false; - } // if we are here, everything worked // call __lldb_init_module(debugger,dict) @@ -2954,7 +2385,7 @@ ScriptInterpreterPython::RunScriptBasedCommand(const char* impl_function, // to set the asynchronous exception - not a desirable situation m_command_thread_state = _PyThreadState_Current; - PythonInputReaderManager py_input(this); + //PythonInputReaderManager py_input(this); ret_val = g_swig_call_command (impl_function, m_dictionary_name.c_str(), @@ -3059,6 +2490,13 @@ ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback swig_init_callb void ScriptInterpreterPython::InitializePrivate () { + static int g_initialized = false; + + if (g_initialized) + return; + + g_initialized = true; + Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__); // Python will muck with STDIN terminal state, so save off any current TTY |