summaryrefslogtreecommitdiffstats
path: root/lldb/source/Interpreter/ScriptInterpreterPython.cpp
diff options
context:
space:
mode:
authorGreg Clayton <gclayton@apple.com>2014-01-27 23:43:24 +0000
committerGreg Clayton <gclayton@apple.com>2014-01-27 23:43:24 +0000
commit44d937820b451296f80449ac3de296345e80f183 (patch)
tree00d14538eded9f7e8bd075128d6ad5fd5ac1caed /lldb/source/Interpreter/ScriptInterpreterPython.cpp
parentf1cb16e481a60dbac58affcf8c8e423dac3937cb (diff)
downloadbcm5719-llvm-44d937820b451296f80449ac3de296345e80f183.tar.gz
bcm5719-llvm-44d937820b451296f80449ac3de296345e80f183.zip
Merging the iohandler branch back into main.
The many many benefits include: 1 - Input/Output/Error streams are now handled as real streams not a push style input 2 - auto completion in python embedded interpreter 3 - multi-line input for "script" and "expression" commands now allow you to edit previous/next lines using up and down arrow keys and this makes multi-line input actually a viable thing to use 4 - it is now possible to use curses to drive LLDB (please try the "gui" command) We will need to deal with and fix any buildbot failures and tests and arise now that input/output and error are correctly hooked up in all cases. llvm-svn: 200263
Diffstat (limited to 'lldb/source/Interpreter/ScriptInterpreterPython.cpp')
-rw-r--r--lldb/source/Interpreter/ScriptInterpreterPython.cpp1520
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
OpenPOWER on IntegriCloud