diff options
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Interpreter')
7 files changed, 1041 insertions, 1339 deletions
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/CommandInterpreter.cpp b/contrib/llvm/tools/lldb/source/Interpreter/CommandInterpreter.cpp index a7c892d..fb0fc7f 100644 --- a/contrib/llvm/tools/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/contrib/llvm/tools/lldb/source/Interpreter/CommandInterpreter.cpp @@ -22,6 +22,7 @@ #include "../Commands/CommandObjectDisassemble.h" #include "../Commands/CommandObjectExpression.h" #include "../Commands/CommandObjectFrame.h" +#include "../Commands/CommandObjectGUI.h" #include "../Commands/CommandObjectHelp.h" #include "../Commands/CommandObjectLog.h" #include "../Commands/CommandObjectMemory.h" @@ -42,11 +43,12 @@ #include "lldb/Core/Debugger.h" -#include "lldb/Core/InputReader.h" #include "lldb/Core/Log.h" #include "lldb/Core/Stream.h" +#include "lldb/Core/StreamFile.h" #include "lldb/Core/Timer.h" +#include "lldb/Host/Editline.h" #include "lldb/Host/Host.h" #include "lldb/Interpreter/Args.h" @@ -99,11 +101,13 @@ CommandInterpreter::CommandInterpreter ) : Broadcaster (&debugger, "lldb.command-interpreter"), Properties(OptionValuePropertiesSP(new OptionValueProperties(ConstString("interpreter")))), + IOHandlerDelegate (IOHandlerDelegate::Completion::LLDBCommand), m_debugger (debugger), m_synchronous_execution (synchronous_execution), m_skip_lldbinit_files (false), m_skip_app_init_files (false), m_script_interpreter_ap (), + m_command_io_handler_sp (), m_comment_char ('#'), m_batch_command_mode (false), m_truncation_warning(eNoTruncation), @@ -376,6 +380,7 @@ CommandInterpreter::LoadCommandDictionary () m_command_dict["disassemble"] = CommandObjectSP (new CommandObjectDisassemble (*this)); m_command_dict["expression"]= CommandObjectSP (new CommandObjectExpression (*this)); m_command_dict["frame"] = CommandObjectSP (new CommandObjectMultiwordFrame (*this)); + m_command_dict["gui"] = CommandObjectSP (new CommandObjectGUI (*this)); m_command_dict["help"] = CommandObjectSP (new CommandObjectHelp (*this)); m_command_dict["log"] = CommandObjectSP (new CommandObjectLog (*this)); m_command_dict["memory"] = CommandObjectSP (new CommandObjectMemory (*this)); @@ -1929,12 +1934,19 @@ CommandInterpreter::HandleCompletionMatches (Args &parsed_line, && matches.GetStringAtIndex(0) != NULL && strcmp (parsed_line.GetArgumentAtIndex(0), matches.GetStringAtIndex(0)) == 0) { - look_for_subcommand = true; - num_command_matches = 0; - matches.DeleteStringAtIndex(0); - parsed_line.AppendArgument (""); - cursor_index++; - cursor_char_position = 0; + if (parsed_line.GetArgumentCount() == 1) + { + word_complete = true; + } + else + { + look_for_subcommand = true; + num_command_matches = 0; + matches.DeleteStringAtIndex(0); + parsed_line.AppendArgument (""); + cursor_index++; + cursor_char_position = 0; + } } } @@ -2023,7 +2035,7 @@ CommandInterpreter::HandleCompletion (const char *current_line, const char *current_elem = partial_parsed_line.GetArgumentAtIndex(cursor_index); if (cursor_char_position == 0 || current_elem[cursor_char_position - 1] != ' ') { - parsed_line.InsertArgumentAtIndex(cursor_index + 1, "", '"'); + parsed_line.InsertArgumentAtIndex(cursor_index + 1, "", '\0'); cursor_index++; cursor_char_position = 0; } @@ -2086,96 +2098,15 @@ CommandInterpreter::~CommandInterpreter () { } -const char * -CommandInterpreter::GetPrompt () -{ - return m_debugger.GetPrompt(); -} - void -CommandInterpreter::SetPrompt (const char *new_prompt) +CommandInterpreter::UpdatePrompt (const char *new_prompt) { - m_debugger.SetPrompt (new_prompt); + EventSP prompt_change_event_sp (new Event(eBroadcastBitResetPrompt, new EventDataBytes (new_prompt)));; + BroadcastEvent (prompt_change_event_sp); + if (m_command_io_handler_sp) + m_command_io_handler_sp->SetPrompt(new_prompt); } -size_t -CommandInterpreter::GetConfirmationInputReaderCallback -( - void *baton, - InputReader &reader, - lldb::InputReaderAction action, - const char *bytes, - size_t bytes_len -) -{ - File &out_file = reader.GetDebugger().GetOutputFile(); - bool *response_ptr = (bool *) baton; - - switch (action) - { - case eInputReaderActivate: - if (out_file.IsValid()) - { - if (reader.GetPrompt()) - { - out_file.Printf ("%s", reader.GetPrompt()); - out_file.Flush (); - } - } - break; - - case eInputReaderDeactivate: - break; - - case eInputReaderReactivate: - if (out_file.IsValid() && reader.GetPrompt()) - { - out_file.Printf ("%s", reader.GetPrompt()); - out_file.Flush (); - } - break; - - case eInputReaderAsynchronousOutputWritten: - break; - - case eInputReaderGotToken: - if (bytes_len == 0) - { - reader.SetIsDone(true); - } - else if (bytes[0] == 'y' || bytes[0] == 'Y') - { - *response_ptr = true; - reader.SetIsDone(true); - } - else if (bytes[0] == 'n' || bytes[0] == 'N') - { - *response_ptr = false; - reader.SetIsDone(true); - } - else - { - if (out_file.IsValid() && !reader.IsDone() && reader.GetPrompt()) - { - out_file.Printf ("Please answer \"y\" or \"n\".\n%s", reader.GetPrompt()); - out_file.Flush (); - } - } - break; - - case eInputReaderInterrupt: - case eInputReaderEndOfFile: - *response_ptr = false; // Assume ^C or ^D means cancel the proposed action - reader.SetIsDone (true); - break; - - case eInputReaderDone: - break; - } - - return bytes_len; - -} bool CommandInterpreter::Confirm (const char *message, bool default_answer) @@ -2183,31 +2114,13 @@ CommandInterpreter::Confirm (const char *message, bool default_answer) // Check AutoConfirm first: if (m_debugger.GetAutoConfirm()) return default_answer; - - InputReaderSP reader_sp (new InputReader(GetDebugger())); - bool response = default_answer; - if (reader_sp) - { - std::string prompt(message); - prompt.append(": ["); - if (default_answer) - prompt.append ("Y/n] "); - else - prompt.append ("y/N] "); - - Error err (reader_sp->Initialize (CommandInterpreter::GetConfirmationInputReaderCallback, - &response, // baton - eInputReaderGranularityLine, // token size, to pass to callback function - NULL, // end token - prompt.c_str(), // prompt - true)); // echo input - if (err.Success()) - { - GetDebugger().PushInputReader (reader_sp); - } - reader_sp->WaitOnReaderIsDone(); - } - return response; + + IOHandlerConfirm *confirm = new IOHandlerConfirm(m_debugger, + message, + default_answer); + IOHandlerSP io_handler_sp (confirm); + m_debugger.RunIOHandler (io_handler_sp); + return confirm->GetResponse(); } OptionArgVectorSP @@ -2477,13 +2390,16 @@ CommandInterpreter::SourceInitFile (bool in_cwd, CommandReturnObject &result) if (init_file.Exists()) { - ExecutionContext *exe_ctx = NULL; // We don't have any context yet. - bool stop_on_continue = true; - bool stop_on_error = false; - bool echo_commands = false; - bool print_results = false; - - HandleCommandsFromFile (init_file, exe_ctx, stop_on_continue, stop_on_error, echo_commands, print_results, eLazyBoolNo, result); + const bool saved_batch = SetBatchCommandMode (true); + HandleCommandsFromFile (init_file, + NULL, // Execution context + eLazyBoolYes, // Stop on continue + eLazyBoolNo, // Stop on error + eLazyBoolNo, // Don't echo commands + eLazyBoolNo, // Don't print command output + eLazyBoolNo, // Don't add the commands that are sourced into the history buffer + result); + SetBatchCommandMode (saved_batch); } else { @@ -2546,8 +2462,8 @@ CommandInterpreter::HandleCommands (const StringList &commands, if (echo_commands) { result.AppendMessageWithFormat ("%s %s\n", - GetPrompt(), - cmd); + m_debugger.GetPrompt(), + cmd); } CommandReturnObject tmp_result; @@ -2631,30 +2547,145 @@ CommandInterpreter::HandleCommands (const StringList &commands, return; } +// Make flags that we can pass into the IOHandler so our delegates can do the right thing +enum { + eHandleCommandFlagStopOnContinue = (1u << 0), + eHandleCommandFlagStopOnError = (1u << 1), + eHandleCommandFlagEchoCommand = (1u << 2), + eHandleCommandFlagPrintResult = (1u << 3) +}; + void CommandInterpreter::HandleCommandsFromFile (FileSpec &cmd_file, ExecutionContext *context, - bool stop_on_continue, - bool stop_on_error, - bool echo_command, - bool print_result, + LazyBool stop_on_continue, + LazyBool stop_on_error, + LazyBool echo_command, + LazyBool print_result, LazyBool add_to_history, CommandReturnObject &result) { if (cmd_file.Exists()) { - bool success; - StringList commands; - success = commands.ReadFileLines(cmd_file); - if (!success) + StreamFileSP input_file_sp (new StreamFile()); + + std::string cmd_file_path = cmd_file.GetPath(); + Error error = input_file_sp->GetFile().Open(cmd_file_path.c_str(), File::eOpenOptionRead); + + if (error.Success()) { - result.AppendErrorWithFormat ("Error reading commands from file: %s.\n", cmd_file.GetFilename().AsCString()); + Debugger &debugger = GetDebugger(); + + uint32_t flags = 0; + + if (stop_on_continue == eLazyBoolCalculate) + { + if (m_command_source_flags.empty()) + { + // Stop on continue by default + flags |= eHandleCommandFlagStopOnContinue; + } + else if (m_command_source_flags.back() & eHandleCommandFlagStopOnContinue) + { + flags |= eHandleCommandFlagStopOnContinue; + } + } + else if (stop_on_continue == eLazyBoolYes) + { + flags |= eHandleCommandFlagStopOnContinue; + } + + if (stop_on_error == eLazyBoolCalculate) + { + if (m_command_source_flags.empty()) + { + if (GetStopCmdSourceOnError()) + flags |= eHandleCommandFlagStopOnError; + } + else if (m_command_source_flags.back() & eHandleCommandFlagStopOnError) + { + flags |= eHandleCommandFlagStopOnError; + } + } + else if (stop_on_error == eLazyBoolYes) + { + flags |= eHandleCommandFlagStopOnError; + } + + if (echo_command == eLazyBoolCalculate) + { + if (m_command_source_flags.empty()) + { + // Echo command by default + flags |= eHandleCommandFlagEchoCommand; + } + else if (m_command_source_flags.back() & eHandleCommandFlagEchoCommand) + { + flags |= eHandleCommandFlagEchoCommand; + } + } + else if (echo_command == eLazyBoolYes) + { + flags |= eHandleCommandFlagEchoCommand; + } + + if (print_result == eLazyBoolCalculate) + { + if (m_command_source_flags.empty()) + { + // Print output by default + flags |= eHandleCommandFlagPrintResult; + } + else if (m_command_source_flags.back() & eHandleCommandFlagPrintResult) + { + flags |= eHandleCommandFlagPrintResult; + } + } + else if (print_result == eLazyBoolYes) + { + flags |= eHandleCommandFlagPrintResult; + } + + if (flags & eHandleCommandFlagPrintResult) + { + debugger.GetOutputFile()->Printf("Executing commands in '%s'.\n", cmd_file_path.c_str()); + } + + // Used for inheriting the right settings when "command source" might have + // nested "command source" commands + lldb::StreamFileSP empty_stream_sp; + m_command_source_flags.push_back(flags); + IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger, + input_file_sp, + empty_stream_sp, // Pass in an empty stream so we inherit the top input reader output stream + empty_stream_sp, // Pass in an empty stream so we inherit the top input reader error stream + flags, + NULL, // Pass in NULL for "editline_name" so no history is saved, or written + debugger.GetPrompt(), + false, // Not multi-line + *this)); + const bool old_async_execution = debugger.GetAsyncExecution(); + + // Set synchronous execution if we not stopping when we continue + if ((flags & eHandleCommandFlagStopOnContinue) == 0) + debugger.SetAsyncExecution (false); + + m_command_source_depth++; + + debugger.RunIOHandler(io_handler_sp); + if (!m_command_source_flags.empty()) + m_command_source_flags.pop_back(); + m_command_source_depth--; + result.SetStatus (eReturnStatusSuccessFinishNoResult); + debugger.SetAsyncExecution (old_async_execution); + } + else + { + result.AppendErrorWithFormat ("error: an error occurred read file '%s': %s\n", cmd_file_path.c_str(), error.AsCString()); result.SetStatus (eReturnStatusFailed); - return; } - m_command_source_depth++; - HandleCommands (commands, context, stop_on_continue, stop_on_error, echo_command, print_result, add_to_history, result); - m_command_source_depth--; + + } else { @@ -2894,7 +2925,6 @@ CommandInterpreter::FindCommandsForApropos (const char *search_word, StringList } } - void CommandInterpreter::UpdateExecutionContext (ExecutionContext *override_context) { @@ -2908,3 +2938,195 @@ CommandInterpreter::UpdateExecutionContext (ExecutionContext *override_context) m_exe_ctx_ref.SetTargetPtr (m_debugger.GetSelectedTarget().get(), adopt_selected); } } + + +size_t +CommandInterpreter::GetProcessOutput () +{ + // The process has stuff waiting for stderr; get it and write it out to the appropriate place. + char stdio_buffer[1024]; + size_t len; + size_t total_bytes = 0; + Error error; + TargetSP target_sp (m_debugger.GetTargetList().GetSelectedTarget()); + if (target_sp) + { + ProcessSP process_sp (target_sp->GetProcessSP()); + if (process_sp) + { + while ((len = process_sp->GetSTDOUT (stdio_buffer, sizeof (stdio_buffer), error)) > 0) + { + size_t bytes_written = len; + m_debugger.GetOutputFile()->Write (stdio_buffer, bytes_written); + total_bytes += len; + } + while ((len = process_sp->GetSTDERR (stdio_buffer, sizeof (stdio_buffer), error)) > 0) + { + size_t bytes_written = len; + m_debugger.GetErrorFile()->Write (stdio_buffer, bytes_written); + total_bytes += len; + } + } + } + return total_bytes; +} + +void +CommandInterpreter::IOHandlerInputComplete (IOHandler &io_handler, std::string &line) +{ + const bool is_interactive = io_handler.GetIsInteractive(); + if (is_interactive == false) + { + // When we are not interactive, don't execute blank lines. This will happen + // sourcing a commands file. We don't want blank lines to repeat the previous + // command and cause any errors to occur (like redefining an alias, get an error + // and stop parsing the commands file). + if (line.empty()) + return; + + // When using a non-interactive file handle (like when sourcing commands from a file) + // we need to echo the command out so we don't just see the command output and no + // command... + if (io_handler.GetFlags().Test(eHandleCommandFlagEchoCommand)) + io_handler.GetOutputStreamFile()->Printf("%s%s\n", io_handler.GetPrompt(), line.c_str()); + } + + lldb_private::CommandReturnObject result; + HandleCommand(line.c_str(), eLazyBoolCalculate, result); + + // Now emit the command output text from the command we just executed + if (io_handler.GetFlags().Test(eHandleCommandFlagPrintResult)) + { + // Display any STDOUT/STDERR _prior_ to emitting the command result text + GetProcessOutput (); + + if (!result.GetImmediateOutputStream()) + { + const char *output = result.GetOutputData(); + if (output && output[0]) + io_handler.GetOutputStreamFile()->PutCString(output); + } + + // Now emit the command error text from the command we just executed + if (!result.GetImmediateErrorStream()) + { + const char *error = result.GetErrorData(); + if (error && error[0]) + io_handler.GetErrorStreamFile()->PutCString(error); + } + } + + switch (result.GetStatus()) + { + case eReturnStatusInvalid: + case eReturnStatusSuccessFinishNoResult: + case eReturnStatusSuccessFinishResult: + case eReturnStatusStarted: + break; + + case eReturnStatusSuccessContinuingNoResult: + case eReturnStatusSuccessContinuingResult: + if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnContinue)) + io_handler.SetIsDone(true); + break; + + case eReturnStatusFailed: + if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnError)) + io_handler.SetIsDone(true); + break; + + case eReturnStatusQuit: + io_handler.SetIsDone(true); + break; + } +} + +void +CommandInterpreter::GetLLDBCommandsFromIOHandler (const char *prompt, + IOHandlerDelegate &delegate, + bool asynchronously, + void *baton) +{ + Debugger &debugger = GetDebugger(); + IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger, + "lldb", // Name of input reader for history + prompt, // Prompt + true, // Get multiple lines + delegate)); // IOHandlerDelegate + + if (io_handler_sp) + { + io_handler_sp->SetUserData (baton); + if (asynchronously) + debugger.PushIOHandler(io_handler_sp); + else + debugger.RunIOHandler(io_handler_sp); + } + +} + + +void +CommandInterpreter::GetPythonCommandsFromIOHandler (const char *prompt, + IOHandlerDelegate &delegate, + bool asynchronously, + void *baton) +{ + Debugger &debugger = GetDebugger(); + IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger, + "lldb-python", // Name of input reader for history + prompt, // Prompt + true, // Get multiple lines + delegate)); // IOHandlerDelegate + + if (io_handler_sp) + { + io_handler_sp->SetUserData (baton); + if (asynchronously) + debugger.PushIOHandler(io_handler_sp); + else + debugger.RunIOHandler(io_handler_sp); + } + +} + +bool +CommandInterpreter::IsActive () +{ + return m_debugger.IsTopIOHandler (m_command_io_handler_sp); +} + +void +CommandInterpreter::RunCommandInterpreter(bool auto_handle_events, + bool spawn_thread) +{ + const bool multiple_lines = false; // Only get one line at a time + if (!m_command_io_handler_sp) + m_command_io_handler_sp.reset(new IOHandlerEditline (m_debugger, + m_debugger.GetInputFile(), + m_debugger.GetOutputFile(), + m_debugger.GetErrorFile(), + eHandleCommandFlagEchoCommand | eHandleCommandFlagPrintResult, + "lldb", + m_debugger.GetPrompt(), + multiple_lines, + *this)); + m_debugger.PushIOHandler(m_command_io_handler_sp); + + if (auto_handle_events) + m_debugger.StartEventHandlerThread(); + + if (spawn_thread) + { + m_debugger.StartIOHandlerThread(); + } + else + { + m_debugger.ExecuteIOHanders(); + + if (auto_handle_events) + m_debugger.StopEventHandlerThread(); + } + +} + diff --git a/contrib/llvm/tools/lldb/source/Interpreter/CommandObject.cpp b/contrib/llvm/tools/lldb/source/Interpreter/CommandObject.cpp index c71ca28..c699536 100644 --- a/contrib/llvm/tools/lldb/source/Interpreter/CommandObject.cpp +++ b/contrib/llvm/tools/lldb/source/Interpreter/CommandObject.cpp @@ -261,13 +261,7 @@ CommandObject::CheckRequirements (CommandReturnObject &result) { Target *target = m_exe_ctx.GetTargetPtr(); if (target) - { - if (m_api_locker.TryLock (target->GetAPIMutex(), NULL) == false) - { - result.AppendError ("failed to get API lock"); - return false; - } - } + m_api_locker.Lock (target->GetAPIMutex()); } } diff --git a/contrib/llvm/tools/lldb/source/Interpreter/Options.cpp b/contrib/llvm/tools/lldb/source/Interpreter/Options.cpp index 8d245cc..c6c66d8 100644 --- a/contrib/llvm/tools/lldb/source/Interpreter/Options.cpp +++ b/contrib/llvm/tools/lldb/source/Interpreter/Options.cpp @@ -952,7 +952,7 @@ Options::HandleOptionArgumentCompletion // If this is the "shlib" option and there was an argument provided, // restrict it to that shared library. - if (strcmp(cur_opt_name, "shlib") == 0 && cur_arg_pos != -1) + if (cur_opt_name && strcmp(cur_opt_name, "shlib") == 0 && cur_arg_pos != -1) { const char *module_name = input.GetArgumentAtIndex(cur_arg_pos); if (module_name) diff --git a/contrib/llvm/tools/lldb/source/Interpreter/PythonDataObjects.cpp b/contrib/llvm/tools/lldb/source/Interpreter/PythonDataObjects.cpp index 1e2bd23..053ff34 100644 --- a/contrib/llvm/tools/lldb/source/Interpreter/PythonDataObjects.cpp +++ b/contrib/llvm/tools/lldb/source/Interpreter/PythonDataObjects.cpp @@ -84,6 +84,12 @@ PythonObject::Str () return PythonString(str); } +bool +PythonObject::IsNULLOrNone () const +{ + return ((m_py_obj == nullptr) || (m_py_obj == Py_None)); +} + //---------------------------------------------------------------------- // PythonString //---------------------------------------------------------------------- @@ -97,7 +103,7 @@ PythonString::PythonString (PyObject *py_obj) : PythonString::PythonString (const PythonObject &object) : PythonObject() { - Reset(object.GetPythonObject()); // Use "Reset()" to ensure that py_obj is a string + Reset(object.get()); // Use "Reset()" to ensure that py_obj is a string } PythonString::PythonString (const lldb::ScriptInterpreterObjectSP &script_object_sp) : @@ -166,7 +172,7 @@ PythonInteger::PythonInteger (PyObject *py_obj) : PythonInteger::PythonInteger (const PythonObject &object) : PythonObject() { - Reset(object.GetPythonObject()); // Use "Reset()" to ensure that py_obj is a integer type + Reset(object.get()); // Use "Reset()" to ensure that py_obj is a integer type } PythonInteger::PythonInteger (const lldb::ScriptInterpreterObjectSP &script_object_sp) : @@ -223,8 +229,8 @@ PythonInteger::SetInteger (int64_t value) // PythonList //---------------------------------------------------------------------- -PythonList::PythonList () : - PythonObject(PyList_New(0)) +PythonList::PythonList (bool create_empty) : + PythonObject(create_empty ? PyList_New(0) : NULL) { } @@ -243,7 +249,7 @@ PythonList::PythonList (PyObject *py_obj) : PythonList::PythonList (const PythonObject &object) : PythonObject() { - Reset(object.GetPythonObject()); // Use "Reset()" to ensure that py_obj is a list + Reset(object.get()); // Use "Reset()" to ensure that py_obj is a list } PythonList::PythonList (const lldb::ScriptInterpreterObjectSP &script_object_sp) : @@ -280,29 +286,29 @@ PythonList::GetItemAtIndex (uint32_t index) { if (m_py_obj) return PythonObject(PyList_GetItem(m_py_obj, index)); - return NULL; + return PythonObject(); } void PythonList::SetItemAtIndex (uint32_t index, const PythonObject & object) { if (m_py_obj && object) - PyList_SetItem(m_py_obj, index, object.GetPythonObject()); + PyList_SetItem(m_py_obj, index, object.get()); } void PythonList::AppendItem (const PythonObject &object) { if (m_py_obj && object) - PyList_Append(m_py_obj, object.GetPythonObject()); + PyList_Append(m_py_obj, object.get()); } //---------------------------------------------------------------------- // PythonDictionary //---------------------------------------------------------------------- -PythonDictionary::PythonDictionary () : - PythonObject(PyDict_New()) +PythonDictionary::PythonDictionary (bool create_empty) : +PythonObject(create_empty ? PyDict_New() : NULL) { } @@ -316,7 +322,7 @@ PythonDictionary::PythonDictionary (PyObject *py_obj) : PythonDictionary::PythonDictionary (const PythonObject &object) : PythonObject() { - Reset(object.GetPythonObject()); // Use "Reset()" to ensure that py_obj is a dictionary + Reset(object.get()); // Use "Reset()" to ensure that py_obj is a dictionary } PythonDictionary::PythonDictionary (const lldb::ScriptInterpreterObjectSP &script_object_sp) : @@ -356,7 +362,7 @@ PythonDictionary::GetItemForKey (const char *key) const PythonString python_key(key); return GetItemForKey(python_key); } - return NULL; + return PythonObject(); } @@ -364,7 +370,7 @@ PythonObject PythonDictionary::GetItemForKey (const PythonString &key) const { if (m_py_obj && key) - return PythonObject(PyDict_GetItem(m_py_obj, key.GetPythonObject())); + return PythonObject(PyDict_GetItem(m_py_obj, key.get())); return PythonObject(); } @@ -374,7 +380,7 @@ PythonDictionary::GetItemForKeyAsString (const PythonString &key, const char *fa { if (m_py_obj && key) { - PyObject *py_obj = PyDict_GetItem(m_py_obj, key.GetPythonObject()); + PyObject *py_obj = PyDict_GetItem(m_py_obj, key.get()); if (py_obj && PyString_Check(py_obj)) return PyString_AsString(py_obj); } @@ -386,7 +392,7 @@ PythonDictionary::GetItemForKeyAsInteger (const PythonString &key, int64_t fail_ { if (m_py_obj && key) { - PyObject *py_obj = PyDict_GetItem(m_py_obj, key.GetPythonObject()); + PyObject *py_obj = PyDict_GetItem(m_py_obj, key.get()); if (py_obj) { if (PyInt_Check(py_obj)) @@ -404,7 +410,7 @@ PythonDictionary::GetKeys () const { if (m_py_obj) return PythonList(PyDict_Keys(m_py_obj)); - return PythonList(); + return PythonList(true); } PythonString @@ -431,7 +437,7 @@ PythonDictionary::GetValueAtPosition (uint32_t pos) const Py_ssize_t pos_iter = 0; if (!m_py_obj) - return NULL; + return PythonObject(); while (PyDict_Next(m_py_obj, &pos_iter, &key, &value)) { if (pos-- == 0) @@ -441,10 +447,17 @@ PythonDictionary::GetValueAtPosition (uint32_t pos) const } void +PythonDictionary::SetItemForKey (const PythonString &key, PyObject *value) +{ + if (m_py_obj && key && value) + PyDict_SetItem(m_py_obj, key.get(), value); +} + +void PythonDictionary::SetItemForKey (const PythonString &key, const PythonObject &value) { if (m_py_obj && key && value) - PyDict_SetItem(m_py_obj, key.GetPythonObject(), value.GetPythonObject()); + PyDict_SetItem(m_py_obj, key.get(), value.get()); } #endif diff --git a/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreterNone.cpp b/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreterNone.cpp index 6a44114..e33480d 100644 --- a/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreterNone.cpp +++ b/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreterNone.cpp @@ -11,6 +11,7 @@ #include "lldb/Interpreter/ScriptInterpreterNone.h" #include "lldb/Core/Stream.h" +#include "lldb/Core/StreamFile.h" #include "lldb/Core/StringList.h" #include "lldb/Core/Debugger.h" #include "lldb/Interpreter/CommandInterpreter.h" @@ -30,14 +31,14 @@ ScriptInterpreterNone::~ScriptInterpreterNone () bool ScriptInterpreterNone::ExecuteOneLine (const char *command, CommandReturnObject *, const ExecuteScriptOptions&) { - m_interpreter.GetDebugger().GetErrorStream().PutCString ("error: there is no embedded script interpreter in this mode.\n"); + m_interpreter.GetDebugger().GetErrorFile()->PutCString ("error: there is no embedded script interpreter in this mode.\n"); return false; } void ScriptInterpreterNone::ExecuteInterpreterLoop () { - m_interpreter.GetDebugger().GetErrorStream().PutCString ("error: there is no embedded script interpreter in this mode.\n"); + m_interpreter.GetDebugger().GetErrorFile()->PutCString ("error: there is no embedded script interpreter in this mode.\n"); } diff --git a/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreterPython.cpp b/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreterPython.cpp index fb60fed..c1d28e8 100644 --- a/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreterPython.cpp +++ b/contrib/llvm/tools/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, 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(uint16_t on_entry_flags, 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 (on_entry_flags, 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; @@ -425,72 +190,130 @@ ScriptInterpreterPython::ScriptInterpreterPython (CommandInterpreter &interprete run_string.Clear(); run_string.Printf ("run_one_line (%s, 'import lldb.formatters, lldb.formatters.cpp, pydoc')", m_dictionary_name.c_str()); PyRun_SimpleString (run_string.GetData()); + run_string.Clear(); int new_count = Debugger::TestDebuggerRefCount(); if (new_count > old_count) Debugger::Terminate(); + run_string.Printf ("run_one_line (%s, 'import lldb.embedded_interpreter; from lldb.embedded_interpreter import run_python_interpreter; from lldb.embedded_interpreter import run_one_line')", m_dictionary_name.c_str()); + PyRun_SimpleString (run_string.GetData()); run_string.Clear(); + 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 +352,24 @@ 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); + m_saved_stdin.Reset (); + } + if (m_saved_stdout) + { + sys_module_dict.SetItemForKey("stdout", m_saved_stdout); + m_saved_stdout.Reset (); + } + if (m_saved_stderr) + { + sys_module_dict.SetItemForKey("stderr", m_saved_stderr); + m_saved_stderr.Reset (); + } } } @@ -545,7 +377,10 @@ ScriptInterpreterPython::LeaveSession () } bool -ScriptInterpreterPython::EnterSession (bool init_lldb_globals) +ScriptInterpreterPython::EnterSession (uint16_t on_entry_flags, + 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. @@ -553,19 +388,19 @@ ScriptInterpreterPython::EnterSession (bool init_lldb_globals) if (m_session_is_active) { if (log) - log->Printf("ScriptInterpreterPython::EnterSession(init_lldb_globals=%i) session is already active, returning without doing anything", init_lldb_globals); + log->Printf("ScriptInterpreterPython::EnterSession(on_entry_flags=0x%" PRIx16 ") session is already active, returning without doing anything", on_entry_flags); return false; } if (log) - log->Printf("ScriptInterpreterPython::EnterSession(init_lldb_globals=%i)", init_lldb_globals); + log->Printf("ScriptInterpreterPython::EnterSession(on_entry_flags=0x%" PRIx16 ")", on_entry_flags); m_session_is_active = true; StreamString run_string; - if (init_lldb_globals) + if (on_entry_flags & Locker::InitGlobals) { 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()); @@ -578,26 +413,61 @@ 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 && (on_entry_flags & Locker::NoSTDIN) == 0) + 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")); + + PyObject *new_file = PyFile_FromFile (in, (char *) "", (char *) "r", 0); + sys_module_dict.SetItemForKey ("stdin", new_file); + Py_DECREF (new_file); } + 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")); + + PyObject *new_file = PyFile_FromFile (out, (char *) "", (char *) "w", 0); + sys_module_dict.SetItemForKey ("stdout", new_file); + Py_DECREF (new_file); + } + 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")); + + PyObject *new_file = PyFile_FromFile (err, (char *) "", (char *) "w", 0); + sys_module_dict.SetItemForKey ("stderr", new_file); + Py_DECREF (new_file); + } + else + m_saved_stderr.Reset(); } if (PyErr_Occurred()) @@ -606,44 +476,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 +533,154 @@ 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; - - // 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; - - if (command) + + if (command && command[0]) { - // 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) + // 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(); + + 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()) { - PyObject *pfunc = (PyObject*)m_run_one_line; - PyObject *pmod = PyImport_AddModule ("lldb.embedded_interpreter"); - if (pmod != NULL) + if (result) { - PyObject *pmod_dict = PyModule_GetDict (pmod); - if ((pmod_dict != NULL) - && PyDict_Check (pmod_dict)) + 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) { - if (!pfunc) + std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor(pipe_fds[0], true)); + if (conn_ap->IsConnected()) { - PyObject *key, *value; - Py_ssize_t pos = 0; + 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); - while (PyDict_Next (pmod_dict, &pos, &key, &value)) - { - Py_INCREF (key); - Py_INCREF (value); - if (strcmp (PyString_AsString (key), "run_one_line") == 0) - { - pfunc = value; - break; - } - } - m_run_one_line = pfunc; + result->SetImmediateOutputFile(debugger.GetOutputFile()->GetFile().GetStream()); + result->SetImmediateErrorFile(debugger.GetErrorFile()->GetFile().GetStream()); } - - if (pfunc && PyCallable_Check (pfunc)) + } + } + 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; + } + + 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. + PythonDictionary &session_dict = GetSessionDictionary (); + if (session_dict) + { + if (GetEmbeddedInterpreterModuleObjects ()) + { + PyObject *pfunc = m_run_one_line_function.get(); + + if (pfunc && PyCallable_Check (pfunc)) + { + PythonObject pargs (Py_BuildValue("(Os)", session_dict.get(), command)); + if (pargs) { - PyObject *pargs = Py_BuildValue("(Os)",script_interpreter_dict,command); - if (pargs != NULL) + PythonObject return_value(PyObject_CallObject (pfunc, pargs.get())); + if (return_value) + success = true; + 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 the write end of the pipe since we are done with our + // one line script. This should cause the read thread that + // output_comm is using to exit + output_file_sp->GetFile().Close(); + // The close above should cause this thread to exit when it gets + // to the end of file, so let it get all its data + output_comm.JoinReadThread(); + // Now we can close the read end of the pipe + output_comm.Disconnect(); + } + + if (success) return true; @@ -755,155 +695,113 @@ 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; - - case eInputReaderAsynchronousOutputWritten: - break; + virtual void + Hide () + { - case eInputReaderInterrupt: - ::write (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor(), "raise KeyboardInterrupt\n", 24); - break; + } + + virtual void + Refresh () + { - 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 + Cancel () + { - 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; -} + virtual void + Interrupt () + { + + } + + virtual void + GotEOF() + { + + } +protected: + ScriptInterpreterPython *m_python; +}; void @@ -918,24 +816,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 +838,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 +861,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 +992,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 +1032,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 +1044,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 +1142,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 @@ -1700,7 +1294,9 @@ ScriptInterpreterPython::OSPlugin_CreatePluginObject (const char *class_name, ll void* ret_val; { - Locker py_lock(this,Locker::AcquireLock,Locker::FreeLock); + Locker py_lock (this, + Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); ret_val = g_swig_create_os_plugin (class_name, m_dictionary_name.c_str(), process_sp); @@ -1712,7 +1308,9 @@ ScriptInterpreterPython::OSPlugin_CreatePluginObject (const char *class_name, ll lldb::ScriptInterpreterObjectSP ScriptInterpreterPython::OSPlugin_RegisterInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp) { - Locker py_lock(this,Locker::AcquireLock,Locker::FreeLock); + Locker py_lock(this, + Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); static char callee_name[] = "get_register_info"; @@ -1771,7 +1369,9 @@ ScriptInterpreterPython::OSPlugin_RegisterInfo (lldb::ScriptInterpreterObjectSP lldb::ScriptInterpreterObjectSP ScriptInterpreterPython::OSPlugin_ThreadsInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp) { - Locker py_lock(this,Locker::AcquireLock,Locker::FreeLock); + Locker py_lock (this, + Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); static char callee_name[] = "get_thread_info"; @@ -1857,7 +1457,9 @@ lldb::ScriptInterpreterObjectSP ScriptInterpreterPython::OSPlugin_RegisterContextData (lldb::ScriptInterpreterObjectSP os_plugin_object_sp, lldb::tid_t tid) { - Locker py_lock(this,Locker::AcquireLock,Locker::FreeLock); + Locker py_lock (this, + Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); static char callee_name[] = "get_register_data"; static char *param_format = const_cast<char *>(GetPythonValueFormatString(tid)); @@ -1919,7 +1521,9 @@ ScriptInterpreterPython::OSPlugin_CreateThread (lldb::ScriptInterpreterObjectSP lldb::tid_t tid, lldb::addr_t context) { - Locker py_lock(this,Locker::AcquireLock,Locker::FreeLock); + Locker py_lock(this, + Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); static char callee_name[] = "create_thread"; std::string param_format; @@ -2011,7 +1615,7 @@ ScriptInterpreterPython::GetDynamicSettings (lldb::ScriptInterpreterObjectSP plu PyObject *reply_pyobj = nullptr; { - Locker py_lock(this); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); TargetSP target_sp(target->shared_from_this()); reply_pyobj = (PyObject*)g_swig_plugin_get(plugin_module_sp->GetObject(),setting_name,target_sp); } @@ -2045,7 +1649,7 @@ ScriptInterpreterPython::CreateSyntheticScriptedProvider (const char *class_name void* ret_val; { - Locker py_lock(this); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); ret_val = g_swig_synthetic_script (class_name, python_interpreter->m_dictionary_name.c_str(), valobj); @@ -2136,14 +1740,14 @@ ScriptInterpreterPython::GetScriptedSummary (const char *python_function_name, && *python_function_name) { { - Locker py_lock(this); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); { - 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()), - valobj, - &new_callee, - retval); + Timer scoped_timer ("g_swig_typescript_callback","g_swig_typescript_callback"); + ret_val = g_swig_typescript_callback (python_function_name, + GetSessionDictionary().get(), + valobj, + &new_callee, + retval); } } } @@ -2188,8 +1792,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); @@ -2201,8 +1804,8 @@ ScriptInterpreterPython::BreakpointCallbackFunction { bool ret_val = true; { - Locker py_lock(python_interpreter); - ret_val = g_swig_breakpoint_callback (python_function_name, + Locker py_lock(python_interpreter, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + ret_val = g_swig_breakpoint_callback (python_function_name, python_interpreter->m_dictionary_name.c_str(), stop_frame_sp, bp_loc_sp); @@ -2243,8 +1846,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); @@ -2254,8 +1856,8 @@ ScriptInterpreterPython::WatchpointCallbackFunction { bool ret_val = true; { - Locker py_lock(python_interpreter); - ret_val = g_swig_watchpoint_callback (python_function_name, + Locker py_lock(python_interpreter, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + ret_val = g_swig_watchpoint_callback (python_function_name, python_interpreter->m_dictionary_name.c_str(), stop_frame_sp, wp_sp); @@ -2269,106 +1871,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) { @@ -2386,7 +1888,7 @@ ScriptInterpreterPython::CalculateNumChildren (const lldb::ScriptInterpreterObje uint32_t ret_val = 0; { - Locker py_lock(this); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); ret_val = g_swig_calc_children (implementor); } @@ -2410,7 +1912,7 @@ ScriptInterpreterPython::GetChildAtIndex (const lldb::ScriptInterpreterObjectSP& lldb::ValueObjectSP ret_val; { - Locker py_lock(this); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); void* child_ptr = g_swig_get_child_index (implementor,idx); if (child_ptr != NULL && child_ptr != Py_None) { @@ -2446,7 +1948,7 @@ ScriptInterpreterPython::GetIndexOfChildWithName (const lldb::ScriptInterpreterO int ret_val = UINT32_MAX; { - Locker py_lock(this); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); ret_val = g_swig_get_index_child (implementor, child_name); } @@ -2470,7 +1972,7 @@ ScriptInterpreterPython::UpdateSynthProviderInstance (const lldb::ScriptInterpre return ret_val; { - Locker py_lock(this); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); ret_val = g_swig_update_provider (implementor); } @@ -2494,7 +1996,7 @@ ScriptInterpreterPython::MightHaveChildrenSynthProviderInstance (const lldb::Scr return ret_val; { - Locker py_lock(this); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); ret_val = g_swig_mighthavechildren_provider (implementor); } @@ -2582,7 +2084,7 @@ ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function, } { ProcessSP process_sp(process->shared_from_this()); - Locker py_lock(this); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); ret_val = g_swig_run_script_keyword_process (impl_function, m_dictionary_name.c_str(), process_sp, output); if (!ret_val) error.SetErrorString("python script evaluation failed"); @@ -2614,7 +2116,7 @@ ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function, } { ThreadSP thread_sp(thread->shared_from_this()); - Locker py_lock(this); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); ret_val = g_swig_run_script_keyword_thread (impl_function, m_dictionary_name.c_str(), thread_sp, output); if (!ret_val) error.SetErrorString("python script evaluation failed"); @@ -2646,7 +2148,7 @@ ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function, } { TargetSP target_sp(target->shared_from_this()); - Locker py_lock(this); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); ret_val = g_swig_run_script_keyword_target (impl_function, m_dictionary_name.c_str(), target_sp, output); if (!ret_val) error.SetErrorString("python script evaluation failed"); @@ -2678,7 +2180,7 @@ ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function, } { StackFrameSP frame_sp(frame->shared_from_this()); - Locker py_lock(this); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); ret_val = g_swig_run_script_keyword_frame (impl_function, m_dictionary_name.c_str(), frame_sp, output); if (!ret_val) error.SetErrorString("python script evaluation failed"); @@ -2728,7 +2230,7 @@ ScriptInterpreterPython::LoadScriptingModule (const char* pathname, // Before executing Pyton code, lock the GIL. Locker py_lock (this, - Locker::AcquireLock | (init_session ? Locker::InitSession : 0), + Locker::AcquireLock | (init_session ? Locker::InitSession : 0) | Locker::NoSTDIN, Locker::FreeAcquiredLock | (init_session ? Locker::TearDownSession : 0)); if (target_file.GetFileType() == FileSpec::eFileTypeInvalid || @@ -2755,7 +2257,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"); @@ -2782,7 +2284,6 @@ ScriptInterpreterPython::LoadScriptingModule (const char* pathname, command_stream.Clear(); command_stream.Printf("sys.modules.__contains__('%s')",basename.c_str()); bool does_contain = false; - int refcount = 0; // this call will succeed if the module was ever imported in any Debugger in the lifetime of the process // in which this LLDB framework is living bool was_imported_globally = (ExecuteOneLineWithReturn(command_stream.GetData(), @@ -2792,10 +2293,7 @@ ScriptInterpreterPython::LoadScriptingModule (const char* pathname, // this call will fail if the module was not imported in this Debugger before command_stream.Clear(); command_stream.Printf("sys.getrefcount(%s)",basename.c_str()); - bool was_imported_locally = (ExecuteOneLineWithReturn(command_stream.GetData(), - ScriptInterpreterPython::eScriptReturnTypeInt, - &refcount, - ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false).SetSetLLDBGlobals(false)) && refcount > 0); + bool was_imported_locally = !(GetSessionDictionary().GetItemForKey(basename.c_str()).IsNULLOrNone()); bool was_imported = (was_imported_globally || was_imported_locally); @@ -2818,47 +2316,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 +2414,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(), @@ -3007,8 +2467,8 @@ std::unique_ptr<ScriptInterpreterLocker> ScriptInterpreterPython::AcquireInterpreterLock () { std::unique_ptr<ScriptInterpreterLocker> py_lock(new Locker(this, - Locker::AcquireLock | Locker::InitSession, - Locker::FreeLock | Locker::TearDownSession)); + Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN, + Locker::FreeLock | Locker::TearDownSession)); return py_lock; } @@ -3059,6 +2519,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 @@ -3081,8 +2548,8 @@ ScriptInterpreterPython::InitializePrivate () Py_InitializeEx (0); // Initialize SWIG after setting up python - assert (g_swig_init_callback != NULL); - g_swig_init_callback (); + if (g_swig_init_callback) + g_swig_init_callback (); // Update the path python uses to search for modules to include the current directory. diff --git a/contrib/llvm/tools/lldb/source/Interpreter/embedded_interpreter.py b/contrib/llvm/tools/lldb/source/Interpreter/embedded_interpreter.py index 0e57c1e..bc0dd6d 100644 --- a/contrib/llvm/tools/lldb/source/Interpreter/embedded_interpreter.py +++ b/contrib/llvm/tools/lldb/source/Interpreter/embedded_interpreter.py @@ -1,103 +1,108 @@ -import readline +import __builtin__ import code +import lldb import sys import traceback -class SimpleREPL(code.InteractiveConsole): - def __init__(self, prompt, dict): - code.InteractiveConsole.__init__(self,dict) - self.prompt = prompt - self.loop_exit = False - self.dict = dict +try: + import readline + import rlcompleter +except ImportError: + have_readline = False +else: + have_readline = True + if 'libedit' in readline.__doc__: + readline.parse_and_bind('bind ^I rl_complete') + else: + readline.parse_and_bind('tab: complete') - def interact(self): - try: - sys.ps1 - except AttributeError: - sys.ps1 = ">>> " - try: - sys.ps2 - except AttributeError: - sys.ps2 = "... " +g_builtin_override_called = False - while not self.loop_exit: - try: - self.read_py_command() - except (SystemExit, EOFError): - # EOF while in Python just breaks out to top level. - self.write('\n') - self.loop_exit = True - break - except KeyboardInterrupt: - self.write("\nKeyboardInterrupt\n") - self.resetbuffer() - more = 0 - except: - traceback.print_exc() +class LLDBQuitter(object): + def __init__(self, name): + self.name = name + def __repr__(self): + self() + def __call__(self, code=None): + global g_builtin_override_called + g_builtin_override_called = True + raise SystemExit(-1) - def process_input (self, in_str): - # Canonicalize the format of the input string - temp_str = in_str - temp_str.strip(' \t') - words = temp_str.split() - temp_str = ('').join(words) +def setquit(): + '''Redefine builtin functions 'quit()' and 'exit()' to print a message and raise an EOFError exception.''' + # This function will be called prior to each interactive + # interpreter loop or each single line, so we set the global + # g_builtin_override_called to False so we know if a SystemExit + # is thrown, we can catch it and tell the difference between + # a call to "quit()" or "exit()" and something like + # "sys.exit(123)" + global g_builtin_override_called + g_builtin_override_called = False + __builtin__.quit = LLDBQuitter('quit') + __builtin__.exit = LLDBQuitter('exit') - # Check the input string to see if it was the quit - # command. If so, intercept it, so that it doesn't - # close stdin on us! - if (temp_str.lower() == "quit()" or temp_str.lower() == "exit()"): - self.loop_exit = True - in_str = "raise SystemExit " - return in_str +# When running one line, we might place the string to run in this string +# in case it would be hard to correctly escape a string's contents - def my_raw_input (self, prompt): - stream = sys.stdout - stream.write (prompt) - stream.flush () - try: - line = sys.stdin.readline() - except KeyboardInterrupt: - line = " \n" - except (SystemExit, EOFError): - line = "quit()\n" - if not line: - raise EOFError - if line[-1] == '\n': - line = line[:-1] - return line +g_run_one_line_str = None - def read_py_command(self): - # Read off a complete Python command. - more = 0 - while 1: - if more: - prompt = sys.ps2 - else: - prompt = sys.ps1 - line = self.my_raw_input(prompt) - # Can be None if sys.stdin was redefined - encoding = getattr(sys.stdin, "encoding", None) - if encoding and not isinstance(line, unicode): - line = line.decode(encoding) - line = self.process_input (line) - more = self.push(line) - if not more: - break - def one_line (self, input): - line = self.process_input (input) - more = self.push(line) - if more: - self.write ("Input not a complete line.") - self.resetbuffer() - more = 0 +def get_terminal_size(fd): + try: + import fcntl, termios, struct + hw = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234')) + except: + hw = (0,0) + return hw -def run_python_interpreter (dict): - # Pass in the dictionary, for continuity from one session to the next. - repl = SimpleREPL('>>> ', dict) - repl.interact() +def readfunc_stdio(prompt): + sys.stdout.write(prompt) + return sys.stdin.readline() -def run_one_line (dict, input_string): - repl = SimpleREPL ('', dict) - repl.one_line (input_string) +def run_python_interpreter (local_dict): + # Pass in the dictionary, for continuity from one session to the next. + setquit() + try: + fd = sys.stdin.fileno(); + interacted = False + if get_terminal_size(fd)[1] == 0: + try: + import termios + old = termios.tcgetattr(fd) + if old[3] & termios.ECHO: + # Need to turn off echoing and restore + new = termios.tcgetattr(fd) + new[3] = new[3] & ~termios.ECHO + try: + termios.tcsetattr(fd, termios.TCSADRAIN, new) + interacted = True + code.interact(banner="Python Interactive Interpreter. To exit, type 'quit()', 'exit()'.", readfunc=readfunc_stdio, local=local_dict) + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old) + except: + pass + # Don't need to turn off echoing + if not interacted: + code.interact(banner="Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.", readfunc=readfunc_stdio, local=local_dict) + else: + # We have a real interactive terminal + code.interact(banner="Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.", local=local_dict) + except SystemExit as e: + global g_builtin_override_called + if not g_builtin_override_called: + print 'Script exited with %s' %(e) +def run_one_line (local_dict, input_string): + global g_run_one_line_str + setquit() + try: + repl = code.InteractiveConsole(local_dict); + if input_string: + repl.runsource (input_string) + elif g_run_one_line_str: + repl.runsource (g_run_one_line_str) + + except SystemExit as e: + global g_builtin_override_called + if not g_builtin_override_called: + print 'Script exited with %s' %(e) |