Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -25,7 +25,7 @@ "Enables using new Python scripts for SWIG API generation .") set(LLDB_SOURCE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/source") -set(LLDB_INCLUDE_ROOT "${LLDB_INCLUDE_ROOT}/include") +set(LLDB_INCLUDE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/include") # If we are not building as a part of LLVM, build LLDB as an # standalone project, using LLVM as an external library: Index: cmake/LLDBDependencies.cmake =================================================================== --- cmake/LLDBDependencies.cmake +++ cmake/LLDBDependencies.cmake @@ -53,6 +53,7 @@ lldbPluginOSPython lldbPluginMemoryHistoryASan lldbPluginInstrumentationRuntimeAddressSanitizer + lldbScriptInterpreter ) # Windows-only libraries @@ -107,6 +108,10 @@ ) endif() +if (NOT LLDB_DISABLE_PYTHON) + list(APPEND LLDB_USED_LIBS lldbPythonInterpreter) +endif() + set( CLANG_USED_LIBS clangAnalysis clangAST Index: include/lldb/API/SBBreakpointLocation.h =================================================================== --- include/lldb/API/SBBreakpointLocation.h +++ include/lldb/API/SBBreakpointLocation.h @@ -101,9 +101,6 @@ private: friend class SBBreakpoint; -#ifndef LLDB_DISABLE_PYTHON - friend class lldb_private::ScriptInterpreterPython; -#endif void SetLocation (const lldb::BreakpointLocationSP &break_loc_sp); Index: include/lldb/API/SBCommandInterpreter.h =================================================================== --- include/lldb/API/SBCommandInterpreter.h +++ include/lldb/API/SBCommandInterpreter.h @@ -229,9 +229,6 @@ private: friend class SBDebugger; - static void - InitializeSWIG (); - lldb_private::CommandInterpreter *m_opaque_ptr; }; Index: include/lldb/API/SBFrame.h =================================================================== --- include/lldb/API/SBFrame.h +++ include/lldb/API/SBFrame.h @@ -213,9 +213,6 @@ friend class SBInstruction; friend class SBThread; friend class SBValue; -#ifndef LLDB_DISABLE_PYTHON - friend class lldb_private::ScriptInterpreterPython; -#endif lldb::StackFrameSP GetFrameSP() const; Index: include/lldb/DataFormatters/TypeSummary.h =================================================================== --- include/lldb/DataFormatters/TypeSummary.h +++ include/lldb/DataFormatters/TypeSummary.h @@ -26,7 +26,7 @@ #include "lldb/Core/Error.h" #include "lldb/Core/FormatEntity.h" #include "lldb/Core/ValueObject.h" -#include "lldb/Interpreter/ScriptInterpreterPython.h" +#include "lldb/ScriptInterpreter/ScriptInterpreter.h" #include "lldb/Symbol/Type.h" namespace lldb_private { Index: include/lldb/Interpreter/CommandInterpreter.h =================================================================== --- include/lldb/Interpreter/CommandInterpreter.h +++ include/lldb/Interpreter/CommandInterpreter.h @@ -14,6 +14,7 @@ // C++ Includes // Other libraries and framework includes // Project includes +#include "lldb/lldb-forward.h" #include "lldb/lldb-private.h" #include "lldb/Core/Broadcaster.h" #include "lldb/Core/Debugger.h" @@ -21,7 +22,6 @@ #include "lldb/Core/Log.h" #include "lldb/Interpreter/CommandHistory.h" #include "lldb/Interpreter/CommandObject.h" -#include "lldb/Interpreter/ScriptInterpreter.h" #include "lldb/Core/Event.h" #include "lldb/Interpreter/Args.h" #include "lldb/Core/StringList.h" @@ -696,7 +696,7 @@ OptionArgMap m_alias_options; // Stores any options (with or without arguments) that go with any alias. CommandHistory m_command_history; std::string m_repeat_command; // Stores the command that will be executed for an empty command string. - std::unique_ptr m_script_interpreter_ap; + lldb::ScriptInterpreterUP m_script_interpreter_ap; lldb::IOHandlerSP m_command_io_handler_sp; char m_comment_char; bool m_batch_command_mode; Index: include/lldb/Interpreter/PythonDataObjects.h =================================================================== --- include/lldb/Interpreter/PythonDataObjects.h +++ /dev/null @@ -1,229 +0,0 @@ -//===-- PythonDataObjects.h----------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_PythonDataObjects_h_ -#define liblldb_PythonDataObjects_h_ - -// C Includes -// C++ Includes - -// Other libraries and framework includes -// Project includes -#include "lldb/lldb-defines.h" -#include "lldb/Core/ConstString.h" -#include "lldb/Core/Flags.h" -#include "lldb/Interpreter/OptionValue.h" -#include "lldb/lldb-python.h" - -namespace lldb_private { - - class PythonObject - { - public: - PythonObject () : - m_py_obj(NULL) - { - } - - explicit PythonObject (PyObject* py_obj) : - m_py_obj(NULL) - { - Reset (py_obj); - } - - PythonObject (const PythonObject &rhs) : - m_py_obj(NULL) - { - Reset (rhs.m_py_obj); - } - - explicit PythonObject (const lldb::ScriptInterpreterObjectSP &script_object_sp); - - virtual - ~PythonObject () - { - Reset (NULL); - } - - bool - Reset (const PythonObject &object) - { - return Reset(object.get()); - } - - virtual bool - Reset (PyObject* py_obj = NULL) - { - if (py_obj != m_py_obj) - { - if (Py_IsInitialized()) - Py_XDECREF(m_py_obj); - m_py_obj = py_obj; - if (Py_IsInitialized()) - Py_XINCREF(m_py_obj); - } - return true; - } - - void - Dump () const - { - if (m_py_obj) - _PyObject_Dump (m_py_obj); - else - puts ("NULL"); - } - - void - Dump (Stream &strm) const; - - PyObject* - get () const - { - return m_py_obj; - } - - PythonString - Repr (); - - PythonString - Str (); - - explicit operator bool () const - { - return m_py_obj != NULL; - } - - bool - IsNULLOrNone () const; - - protected: - PyObject* m_py_obj; - }; - - class PythonString: public PythonObject - { - public: - - PythonString (); - PythonString (PyObject *o); - PythonString (const PythonObject &object); - PythonString (const lldb::ScriptInterpreterObjectSP &script_object_sp); - PythonString (const char* string); - virtual ~PythonString (); - - virtual bool - Reset (PyObject* py_obj = NULL); - - const char* - GetString() const; - - size_t - GetSize() const; - - void - SetString (const char* string); - }; - - class PythonInteger: public PythonObject - { - public: - - PythonInteger (); - PythonInteger (PyObject* py_obj); - PythonInteger (const PythonObject &object); - PythonInteger (const lldb::ScriptInterpreterObjectSP &script_object_sp); - PythonInteger (int64_t value); - virtual ~PythonInteger (); - - virtual bool - Reset (PyObject* py_obj = NULL); - - int64_t - GetInteger(); - - void - SetInteger (int64_t value); - }; - - class PythonList: public PythonObject - { - public: - - PythonList (bool create_empty); - PythonList (PyObject* py_obj); - PythonList (const PythonObject &object); - PythonList (const lldb::ScriptInterpreterObjectSP &script_object_sp); - PythonList (uint32_t count); - virtual ~PythonList (); - - virtual bool - Reset (PyObject* py_obj = NULL); - - uint32_t - GetSize(); - - PythonObject - GetItemAtIndex (uint32_t index); - - void - SetItemAtIndex (uint32_t index, const PythonObject &object); - - void - AppendItem (const PythonObject &object); - }; - - class PythonDictionary: public PythonObject - { - public: - - explicit PythonDictionary (bool create_empty); - PythonDictionary (PyObject* object); - PythonDictionary (const PythonObject &object); - PythonDictionary (const lldb::ScriptInterpreterObjectSP &script_object_sp); - virtual ~PythonDictionary (); - - virtual bool - Reset (PyObject* object = NULL); - - uint32_t GetSize(); - - PythonObject - GetItemForKey (const PythonString &key) const; - - const char * - GetItemForKeyAsString (const PythonString &key, const char *fail_value = NULL) const; - - int64_t - GetItemForKeyAsInteger (const PythonString &key, int64_t fail_value = 0) const; - - PythonObject - GetItemForKey (const char *key) const; - - typedef bool (*DictionaryIteratorCallback)(PythonString* key, PythonDictionary* dict); - - PythonList - GetKeys () const; - - PythonString - GetKeyAtPosition (uint32_t pos) const; - - PythonObject - GetValueAtPosition (uint32_t pos) const; - - void - SetItemForKey (const PythonString &key, PyObject *value); - - void - SetItemForKey (const PythonString &key, const PythonObject& value); - }; - -} // namespace lldb_private - -#endif // liblldb_PythonDataObjects_h_ Index: include/lldb/Interpreter/ScriptInterpreter.h =================================================================== --- include/lldb/Interpreter/ScriptInterpreter.h +++ /dev/null @@ -1,668 +0,0 @@ -//===-- ScriptInterpreter.h -------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_ScriptInterpreter_h_ -#define liblldb_ScriptInterpreter_h_ - -#include "lldb/lldb-private.h" - -#include "lldb/Core/Broadcaster.h" -#include "lldb/Core/Error.h" - -#include "lldb/Utility/PseudoTerminal.h" - - -namespace lldb_private { - -class ScriptInterpreterObject -{ -public: - ScriptInterpreterObject() : - m_object(NULL) - {} - - ScriptInterpreterObject(void* obj) : - m_object(obj) - {} - - ScriptInterpreterObject(const ScriptInterpreterObject& rhs) - : m_object(rhs.m_object) - {} - - virtual void* - GetObject() - { - return m_object; - } - - explicit operator bool () - { - return m_object != NULL; - } - - ScriptInterpreterObject& - operator = (const ScriptInterpreterObject& rhs) - { - if (this != &rhs) - m_object = rhs.m_object; - return *this; - } - - virtual - ~ScriptInterpreterObject() - {} - -protected: - void* m_object; -}; - -class ScriptInterpreterLocker -{ -public: - - ScriptInterpreterLocker () - { - } - - virtual ~ScriptInterpreterLocker () - { - } -private: - DISALLOW_COPY_AND_ASSIGN (ScriptInterpreterLocker); -}; - - -class ScriptInterpreter -{ -public: - - typedef void (*SWIGInitCallback) (void); - - typedef bool (*SWIGBreakpointCallbackFunction) (const char *python_function_name, - const char *session_dictionary_name, - const lldb::StackFrameSP& frame_sp, - const lldb::BreakpointLocationSP &bp_loc_sp); - - typedef bool (*SWIGWatchpointCallbackFunction) (const char *python_function_name, - const char *session_dictionary_name, - const lldb::StackFrameSP& frame_sp, - const lldb::WatchpointSP &wp_sp); - - typedef bool (*SWIGPythonTypeScriptCallbackFunction) (const char *python_function_name, - void *session_dictionary, - const lldb::ValueObjectSP& valobj_sp, - void** pyfunct_wrapper, - const lldb::TypeSummaryOptionsSP& options, - std::string& retval); - - typedef void* (*SWIGPythonCreateSyntheticProvider) (const char *python_class_name, - const char *session_dictionary_name, - const lldb::ValueObjectSP& valobj_sp); - - typedef void* (*SWIGPythonCreateScriptedThreadPlan) (const char *python_class_name, - const char *session_dictionary_name, - const lldb::ThreadPlanSP& thread_plan_sp); - - typedef bool (*SWIGPythonCallThreadPlan) (void *implementor, const char *method_name, Event *event_sp, bool &got_error); - - typedef void* (*SWIGPythonCreateOSPlugin) (const char *python_class_name, - const char *session_dictionary_name, - const lldb::ProcessSP& process_sp); - - typedef uint32_t (*SWIGPythonCalculateNumChildren) (void *implementor); - typedef void* (*SWIGPythonGetChildAtIndex) (void *implementor, uint32_t idx); - typedef int (*SWIGPythonGetIndexOfChildWithName) (void *implementor, const char* child_name); - typedef void* (*SWIGPythonCastPyObjectToSBValue) (void* data); - typedef lldb::ValueObjectSP (*SWIGPythonGetValueObjectSPFromSBValue) (void* data); - typedef bool (*SWIGPythonUpdateSynthProviderInstance) (void* data); - typedef bool (*SWIGPythonMightHaveChildrenSynthProviderInstance) (void* data); - typedef void* (*SWIGPythonGetValueSynthProviderInstance) (void *implementor); - - typedef bool (*SWIGPythonCallCommand) (const char *python_function_name, - const char *session_dictionary_name, - lldb::DebuggerSP& debugger, - const char* args, - lldb_private::CommandReturnObject& cmd_retobj, - lldb::ExecutionContextRefSP exe_ctx_ref_sp); - - typedef bool (*SWIGPythonCallModuleInit) (const char *python_module_name, - const char *session_dictionary_name, - lldb::DebuggerSP& debugger); - - typedef bool (*SWIGPythonScriptKeyword_Process) (const char* python_function_name, - const char* session_dictionary_name, - lldb::ProcessSP& process, - std::string& output); - typedef bool (*SWIGPythonScriptKeyword_Thread) (const char* python_function_name, - const char* session_dictionary_name, - lldb::ThreadSP& thread, - std::string& output); - - typedef bool (*SWIGPythonScriptKeyword_Target) (const char* python_function_name, - const char* session_dictionary_name, - lldb::TargetSP& target, - std::string& output); - - typedef bool (*SWIGPythonScriptKeyword_Frame) (const char* python_function_name, - const char* session_dictionary_name, - lldb::StackFrameSP& frame, - std::string& output); - - typedef bool (*SWIGPythonScriptKeyword_Value) (const char* python_function_name, - const char* session_dictionary_name, - lldb::ValueObjectSP& value, - std::string& output); - - typedef void* (*SWIGPython_GetDynamicSetting) (void* module, - const char* setting, - const lldb::TargetSP& target_sp); - - typedef enum - { - eScriptReturnTypeCharPtr, - eScriptReturnTypeBool, - eScriptReturnTypeShortInt, - eScriptReturnTypeShortIntUnsigned, - eScriptReturnTypeInt, - eScriptReturnTypeIntUnsigned, - eScriptReturnTypeLongInt, - eScriptReturnTypeLongIntUnsigned, - eScriptReturnTypeLongLong, - eScriptReturnTypeLongLongUnsigned, - eScriptReturnTypeFloat, - eScriptReturnTypeDouble, - eScriptReturnTypeChar, - eScriptReturnTypeCharStrOrNone, - eScriptReturnTypeOpaqueObject - } ScriptReturnType; - - ScriptInterpreter (CommandInterpreter &interpreter, lldb::ScriptLanguage script_lang); - - virtual ~ScriptInterpreter (); - - struct ExecuteScriptOptions - { - public: - ExecuteScriptOptions () : - m_enable_io(true), - m_set_lldb_globals(true), - m_maskout_errors(true) - { - } - - bool - GetEnableIO () const - { - return m_enable_io; - } - - bool - GetSetLLDBGlobals () const - { - return m_set_lldb_globals; - } - - bool - GetMaskoutErrors () const - { - return m_maskout_errors; - } - - ExecuteScriptOptions& - SetEnableIO (bool enable) - { - m_enable_io = enable; - return *this; - } - - ExecuteScriptOptions& - SetSetLLDBGlobals (bool set) - { - m_set_lldb_globals = set; - return *this; - } - - ExecuteScriptOptions& - SetMaskoutErrors (bool maskout) - { - m_maskout_errors = maskout; - return *this; - } - - private: - bool m_enable_io; - bool m_set_lldb_globals; - bool m_maskout_errors; - }; - - virtual bool - Interrupt() - { - return false; - } - - virtual bool - ExecuteOneLine (const char *command, - CommandReturnObject *result, - const ExecuteScriptOptions &options = ExecuteScriptOptions()) = 0; - - virtual void - ExecuteInterpreterLoop () = 0; - - virtual bool - ExecuteOneLineWithReturn (const char *in_string, - ScriptReturnType return_type, - void *ret_value, - const ExecuteScriptOptions &options = ExecuteScriptOptions()) - { - return true; - } - - virtual Error - ExecuteMultipleLines (const char *in_string, - const ExecuteScriptOptions &options = ExecuteScriptOptions()) - { - Error error; - error.SetErrorString("not implemented"); - return error; - } - - virtual Error - ExportFunctionDefinitionToInterpreter (StringList &function_def) - { - Error error; - error.SetErrorString("not implemented"); - return error; - } - - virtual Error - GenerateBreakpointCommandCallbackData (StringList &input, std::string& output) - { - Error error; - error.SetErrorString("not implemented"); - return error; - } - - virtual bool - GenerateWatchpointCommandCallbackData (StringList &input, std::string& output) - { - return false; - } - - virtual bool - GenerateTypeScriptFunction (const char* oneliner, std::string& output, const void* name_token = NULL) - { - return false; - } - - virtual bool - GenerateTypeScriptFunction (StringList &input, std::string& output, const void* name_token = NULL) - { - return false; - } - - virtual bool - GenerateScriptAliasFunction (StringList &input, std::string& output) - { - return false; - } - - virtual bool - GenerateTypeSynthClass (StringList &input, std::string& output, const void* name_token = NULL) - { - return false; - } - - virtual bool - GenerateTypeSynthClass (const char* oneliner, std::string& output, const void* name_token = NULL) - { - return false; - } - - virtual lldb::ScriptInterpreterObjectSP - CreateSyntheticScriptedProvider (const char *class_name, - lldb::ValueObjectSP valobj) - { - return lldb::ScriptInterpreterObjectSP(); - } - - virtual lldb::ScriptInterpreterObjectSP - OSPlugin_CreatePluginObject (const char *class_name, - lldb::ProcessSP process_sp) - { - return lldb::ScriptInterpreterObjectSP(); - } - - virtual lldb::ScriptInterpreterObjectSP - OSPlugin_RegisterInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp) - { - return lldb::ScriptInterpreterObjectSP(); - } - - virtual lldb::ScriptInterpreterObjectSP - OSPlugin_ThreadsInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp) - { - return lldb::ScriptInterpreterObjectSP(); - } - - virtual lldb::ScriptInterpreterObjectSP - OSPlugin_RegisterContextData (lldb::ScriptInterpreterObjectSP os_plugin_object_sp, - lldb::tid_t thread_id) - { - return lldb::ScriptInterpreterObjectSP(); - } - - virtual lldb::ScriptInterpreterObjectSP - OSPlugin_CreateThread (lldb::ScriptInterpreterObjectSP os_plugin_object_sp, - lldb::tid_t tid, - lldb::addr_t context) - { - return lldb::ScriptInterpreterObjectSP(); - } - - virtual lldb::ScriptInterpreterObjectSP - CreateScriptedThreadPlan (const char *class_name, - lldb::ThreadPlanSP thread_plan_sp) - { - return lldb::ScriptInterpreterObjectSP(); - } - - virtual bool - ScriptedThreadPlanExplainsStop (lldb::ScriptInterpreterObjectSP implementor_sp, - Event *event, - bool &script_error) - { - script_error = true; - return true; - } - - virtual bool - ScriptedThreadPlanShouldStop (lldb::ScriptInterpreterObjectSP implementor_sp, - Event *event, - bool &script_error) - { - script_error = true; - return true; - } - - virtual lldb::StateType - ScriptedThreadPlanGetRunState (lldb::ScriptInterpreterObjectSP implementor_sp, - bool &script_error) - { - script_error = true; - return lldb::eStateStepping; - } - - virtual lldb::ScriptInterpreterObjectSP - LoadPluginModule (const FileSpec& file_spec, - lldb_private::Error& error) - { - return lldb::ScriptInterpreterObjectSP(); - } - - virtual lldb::ScriptInterpreterObjectSP - GetDynamicSettings (lldb::ScriptInterpreterObjectSP plugin_module_sp, - Target* target, - const char* setting_name, - lldb_private::Error& error) - { - return lldb::ScriptInterpreterObjectSP(); - } - - virtual Error - GenerateFunction(const char *signature, const StringList &input) - { - Error error; - error.SetErrorString("unimplemented"); - return error; - } - - virtual void - CollectDataForBreakpointCommandCallback (std::vector &options, - CommandReturnObject &result); - - virtual void - CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options, - CommandReturnObject &result); - - /// Set the specified text as the callback for the breakpoint. - Error - SetBreakpointCommandCallback (std::vector &bp_options_vec, - const char *callback_text); - - virtual Error - SetBreakpointCommandCallback (BreakpointOptions *bp_options, - const char *callback_text) - { - Error error; - error.SetErrorString("unimplemented"); - return error; - } - - void - SetBreakpointCommandCallbackFunction (std::vector &bp_options_vec, - const char *function_name); - - /// Set a one-liner as the callback for the breakpoint. - virtual void - SetBreakpointCommandCallbackFunction (BreakpointOptions *bp_options, - const char *function_name) - { - return; - } - - /// Set a one-liner as the callback for the watchpoint. - virtual void - SetWatchpointCommandCallback (WatchpointOptions *wp_options, - const char *oneliner) - { - return; - } - - virtual bool - GetScriptedSummary (const char *function_name, - lldb::ValueObjectSP valobj, - lldb::ScriptInterpreterObjectSP& callee_wrapper_sp, - const TypeSummaryOptions& options, - std::string& retval) - { - return false; - } - - virtual void - Clear () - { - // Clean up any ref counts to SBObjects that might be in global variables - } - - virtual size_t - CalculateNumChildren (const lldb::ScriptInterpreterObjectSP& implementor) - { - return 0; - } - - virtual lldb::ValueObjectSP - GetChildAtIndex (const lldb::ScriptInterpreterObjectSP& implementor, uint32_t idx) - { - return lldb::ValueObjectSP(); - } - - virtual int - GetIndexOfChildWithName (const lldb::ScriptInterpreterObjectSP& implementor, const char* child_name) - { - return UINT32_MAX; - } - - virtual bool - UpdateSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor) - { - return false; - } - - virtual bool - MightHaveChildrenSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor) - { - return true; - } - - virtual lldb::ValueObjectSP - GetSyntheticValue (const lldb::ScriptInterpreterObjectSP& implementor) - { - return nullptr; - } - - virtual bool - RunScriptBasedCommand (const char* impl_function, - const char* args, - ScriptedCommandSynchronicity synchronicity, - lldb_private::CommandReturnObject& cmd_retobj, - Error& error, - const lldb_private::ExecutionContext& exe_ctx) - { - return false; - } - - virtual bool - RunScriptFormatKeyword (const char* impl_function, - Process* process, - std::string& output, - Error& error) - { - error.SetErrorString("unimplemented"); - return false; - } - - virtual bool - RunScriptFormatKeyword (const char* impl_function, - Thread* thread, - std::string& output, - Error& error) - { - error.SetErrorString("unimplemented"); - return false; - } - - virtual bool - RunScriptFormatKeyword (const char* impl_function, - Target* target, - std::string& output, - Error& error) - { - error.SetErrorString("unimplemented"); - return false; - } - - virtual bool - RunScriptFormatKeyword (const char* impl_function, - StackFrame* frame, - std::string& output, - Error& error) - { - error.SetErrorString("unimplemented"); - return false; - } - - virtual bool - RunScriptFormatKeyword (const char* impl_function, - ValueObject* value, - std::string& output, - Error& error) - { - error.SetErrorString("unimplemented"); - return false; - } - - virtual bool - GetDocumentationForItem (const char* item, std::string& dest) - { - dest.clear(); - return false; - } - - virtual bool - CheckObjectExists (const char* name) - { - return false; - } - - virtual bool - LoadScriptingModule (const char* filename, - bool can_reload, - bool init_session, - lldb_private::Error& error, - lldb::ScriptInterpreterObjectSP* module_sp = nullptr) - { - error.SetErrorString("loading unimplemented"); - return false; - } - - virtual bool - IsReservedWord (const char* word) - { - return false; - } - - virtual lldb::ScriptInterpreterObjectSP - MakeScriptObject (void* object) - { - return lldb::ScriptInterpreterObjectSP(new ScriptInterpreterObject(object)); - } - - virtual std::unique_ptr - AcquireInterpreterLock (); - - const char * - GetScriptInterpreterPtyName (); - - int - GetMasterFileDescriptor (); - - CommandInterpreter & - GetCommandInterpreter (); - - static std::string - LanguageToString (lldb::ScriptLanguage language); - - static void - InitializeInterpreter (SWIGInitCallback python_swig_init_callback, - SWIGBreakpointCallbackFunction swig_breakpoint_callback, - SWIGWatchpointCallbackFunction swig_watchpoint_callback, - SWIGPythonTypeScriptCallbackFunction swig_typescript_callback, - SWIGPythonCreateSyntheticProvider swig_synthetic_script, - SWIGPythonCalculateNumChildren swig_calc_children, - SWIGPythonGetChildAtIndex swig_get_child_index, - SWIGPythonGetIndexOfChildWithName swig_get_index_child, - SWIGPythonCastPyObjectToSBValue swig_cast_to_sbvalue , - SWIGPythonGetValueObjectSPFromSBValue swig_get_valobj_sp_from_sbvalue, - SWIGPythonUpdateSynthProviderInstance swig_update_provider, - SWIGPythonMightHaveChildrenSynthProviderInstance swig_mighthavechildren_provider, - SWIGPythonGetValueSynthProviderInstance swig_getvalue_provider, - SWIGPythonCallCommand swig_call_command, - SWIGPythonCallModuleInit swig_call_module_init, - SWIGPythonCreateOSPlugin swig_create_os_plugin, - SWIGPythonScriptKeyword_Process swig_run_script_keyword_process, - SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread, - SWIGPythonScriptKeyword_Target swig_run_script_keyword_target, - SWIGPythonScriptKeyword_Frame swig_run_script_keyword_frame, - SWIGPythonScriptKeyword_Value swig_run_script_keyword_value, - SWIGPython_GetDynamicSetting swig_plugin_get, - SWIGPythonCreateScriptedThreadPlan swig_thread_plan_script, - SWIGPythonCallThreadPlan swig_call_thread_plan); - - virtual void - ResetOutputFileHandle (FILE *new_fh) { } //By default, do nothing. - -protected: - CommandInterpreter &m_interpreter; - lldb::ScriptLanguage m_script_lang; -}; - -} // namespace lldb_private - -#endif // #ifndef liblldb_ScriptInterpreter_h_ Index: include/lldb/Interpreter/ScriptInterpreterNone.h =================================================================== --- include/lldb/Interpreter/ScriptInterpreterNone.h +++ /dev/null @@ -1,35 +0,0 @@ -//===-- ScriptInterpreterNone.h ---------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_ScriptInterpreterNone_h_ -#define liblldb_ScriptInterpreterNone_h_ - -#include "lldb/Interpreter/ScriptInterpreter.h" - -namespace lldb_private { - -class ScriptInterpreterNone : public ScriptInterpreter -{ -public: - - ScriptInterpreterNone (CommandInterpreter &interpreter); - - ~ScriptInterpreterNone (); - - bool - ExecuteOneLine (const char *command, CommandReturnObject *result, const ExecuteScriptOptions &options = ExecuteScriptOptions()); - - void - ExecuteInterpreterLoop (); - -}; - -} // namespace lldb_private - -#endif // #ifndef liblldb_ScriptInterpreterNone_h_ Index: include/lldb/Interpreter/ScriptInterpreterPython.h =================================================================== --- include/lldb/Interpreter/ScriptInterpreterPython.h +++ /dev/null @@ -1,516 +0,0 @@ -//===-- ScriptInterpreterPython.h -------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - - -#ifndef liblldb_ScriptInterpreterPython_h_ -#define liblldb_ScriptInterpreterPython_h_ - -#ifdef LLDB_DISABLE_PYTHON - -// Python is disabled in this build - -#else - -#include "lldb/lldb-python.h" -#include "lldb/lldb-private.h" -#include "lldb/Core/IOHandler.h" -#include "lldb/Interpreter/ScriptInterpreter.h" -#include "lldb/Interpreter/PythonDataObjects.h" -#include "lldb/Host/Terminal.h" - -class IOHandlerPythonInterpreter; - -namespace lldb_private { - -class ScriptInterpreterPython : - public ScriptInterpreter, - public IOHandlerDelegateMultiline -{ -public: - - friend class IOHandlerPythonInterpreter; - - ScriptInterpreterPython (CommandInterpreter &interpreter); - - ~ScriptInterpreterPython (); - - bool - Interrupt() override; - - bool - ExecuteOneLine (const char *command, - CommandReturnObject *result, - const ExecuteScriptOptions &options = ExecuteScriptOptions()) override; - - void - ExecuteInterpreterLoop () override; - - bool - ExecuteOneLineWithReturn (const char *in_string, - ScriptInterpreter::ScriptReturnType return_type, - void *ret_value, - const ExecuteScriptOptions &options = ExecuteScriptOptions()) override; - - lldb_private::Error - ExecuteMultipleLines (const char *in_string, - const ExecuteScriptOptions &options = ExecuteScriptOptions()) override; - - Error - ExportFunctionDefinitionToInterpreter (StringList &function_def) override; - - bool - GenerateTypeScriptFunction (StringList &input, std::string& output, const void* name_token = NULL) override; - - bool - GenerateTypeSynthClass (StringList &input, std::string& output, const void* name_token = NULL) override; - - bool - GenerateTypeSynthClass (const char* oneliner, std::string& output, const void* name_token = NULL) override; - - // use this if the function code is just a one-liner script - bool - GenerateTypeScriptFunction (const char* oneliner, std::string& output, const void* name_token = NULL) override; - - bool - GenerateScriptAliasFunction (StringList &input, std::string& output) override; - - lldb::ScriptInterpreterObjectSP - CreateSyntheticScriptedProvider (const char *class_name, - lldb::ValueObjectSP valobj) override; - - lldb::ScriptInterpreterObjectSP - CreateScriptedThreadPlan (const char *class_name, - lldb::ThreadPlanSP thread_plan) override; - - bool - ScriptedThreadPlanExplainsStop (lldb::ScriptInterpreterObjectSP implementor_sp, - Event *event, - bool &script_error) override; - bool - ScriptedThreadPlanShouldStop (lldb::ScriptInterpreterObjectSP implementor_sp, - Event *event, - bool &script_error) override; - lldb::StateType - ScriptedThreadPlanGetRunState (lldb::ScriptInterpreterObjectSP implementor_sp, - bool &script_error) override; - - lldb::ScriptInterpreterObjectSP - OSPlugin_CreatePluginObject (const char *class_name, - lldb::ProcessSP process_sp) override; - - lldb::ScriptInterpreterObjectSP - OSPlugin_RegisterInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp) override; - - lldb::ScriptInterpreterObjectSP - OSPlugin_ThreadsInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp) override; - - lldb::ScriptInterpreterObjectSP - OSPlugin_RegisterContextData (lldb::ScriptInterpreterObjectSP os_plugin_object_sp, - lldb::tid_t thread_id) override; - - lldb::ScriptInterpreterObjectSP - OSPlugin_CreateThread (lldb::ScriptInterpreterObjectSP os_plugin_object_sp, - lldb::tid_t tid, - lldb::addr_t context) override; - - lldb::ScriptInterpreterObjectSP - LoadPluginModule (const FileSpec& file_spec, - lldb_private::Error& error) override; - - lldb::ScriptInterpreterObjectSP - GetDynamicSettings (lldb::ScriptInterpreterObjectSP plugin_module_sp, - Target* target, - const char* setting_name, - lldb_private::Error& error) override; - - size_t - CalculateNumChildren (const lldb::ScriptInterpreterObjectSP& implementor) override; - - lldb::ValueObjectSP - GetChildAtIndex (const lldb::ScriptInterpreterObjectSP& implementor, uint32_t idx) override; - - int - GetIndexOfChildWithName (const lldb::ScriptInterpreterObjectSP& implementor, const char* child_name) override; - - bool - UpdateSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor) override; - - bool - MightHaveChildrenSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor) override; - - lldb::ValueObjectSP - GetSyntheticValue (const lldb::ScriptInterpreterObjectSP& implementor) override; - - bool - RunScriptBasedCommand(const char* impl_function, - const char* args, - ScriptedCommandSynchronicity synchronicity, - lldb_private::CommandReturnObject& cmd_retobj, - Error& error, - const lldb_private::ExecutionContext& exe_ctx) override; - - Error - GenerateFunction(const char *signature, const StringList &input) override; - - Error - GenerateBreakpointCommandCallbackData (StringList &input, std::string& output) override; - - bool - GenerateWatchpointCommandCallbackData (StringList &input, std::string& output) override; - -// static size_t -// GenerateBreakpointOptionsCommandCallback (void *baton, -// InputReader &reader, -// lldb::InputReaderAction notification, -// const char *bytes, -// size_t bytes_len); -// -// static size_t -// GenerateWatchpointOptionsCommandCallback (void *baton, -// InputReader &reader, -// lldb::InputReaderAction notification, -// const char *bytes, -// size_t bytes_len); - - static bool - BreakpointCallbackFunction (void *baton, - StoppointCallbackContext *context, - lldb::user_id_t break_id, - lldb::user_id_t break_loc_id); - - static bool - WatchpointCallbackFunction (void *baton, - StoppointCallbackContext *context, - lldb::user_id_t watch_id); - - bool - GetScriptedSummary (const char *function_name, - lldb::ValueObjectSP valobj, - lldb::ScriptInterpreterObjectSP& callee_wrapper_sp, - const TypeSummaryOptions& options, - std::string& retval) override; - - void - Clear () override; - - bool - GetDocumentationForItem (const char* item, std::string& dest) override; - - bool - CheckObjectExists (const char* name) override - { - if (!name || !name[0]) - return false; - std::string temp; - return GetDocumentationForItem (name,temp); - } - - bool - RunScriptFormatKeyword (const char* impl_function, - Process* process, - std::string& output, - Error& error) override; - - bool - RunScriptFormatKeyword (const char* impl_function, - Thread* thread, - std::string& output, - Error& error) override; - - bool - RunScriptFormatKeyword (const char* impl_function, - Target* target, - std::string& output, - Error& error) override; - - bool - RunScriptFormatKeyword (const char* impl_function, - StackFrame* frame, - std::string& output, - Error& error) override; - - bool - RunScriptFormatKeyword (const char* impl_function, - ValueObject* value, - std::string& output, - Error& error) override; - - bool - LoadScriptingModule (const char* filename, - bool can_reload, - bool init_session, - lldb_private::Error& error, - lldb::ScriptInterpreterObjectSP* module_sp = nullptr) override; - - bool - IsReservedWord (const char* word) override; - - lldb::ScriptInterpreterObjectSP - MakeScriptObject (void* object) override; - - std::unique_ptr - AcquireInterpreterLock () override; - - void - CollectDataForBreakpointCommandCallback (std::vector &bp_options_vec, - CommandReturnObject &result) override; - - void - CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options, - CommandReturnObject &result) override; - - /// Set the callback body text into the callback for the breakpoint. - Error - SetBreakpointCommandCallback (BreakpointOptions *bp_options, - const char *callback_body) override; - - void - SetBreakpointCommandCallbackFunction (BreakpointOptions *bp_options, - const char *function_name) override; - - /// Set a one-liner as the callback for the watchpoint. - void - SetWatchpointCommandCallback (WatchpointOptions *wp_options, - const char *oneliner) override; - - StringList - ReadCommandInputFromUser (FILE *in_file); - - virtual void - ResetOutputFileHandle (FILE *new_fh) override; - - static void - InitializePrivate (); - - static void - InitializeInterpreter (SWIGInitCallback python_swig_init_callback, - SWIGBreakpointCallbackFunction swig_breakpoint_callback, - SWIGWatchpointCallbackFunction swig_watchpoint_callback, - SWIGPythonTypeScriptCallbackFunction swig_typescript_callback, - SWIGPythonCreateSyntheticProvider swig_synthetic_script, - SWIGPythonCalculateNumChildren swig_calc_children, - SWIGPythonGetChildAtIndex swig_get_child_index, - SWIGPythonGetIndexOfChildWithName swig_get_index_child, - SWIGPythonCastPyObjectToSBValue swig_cast_to_sbvalue , - SWIGPythonGetValueObjectSPFromSBValue swig_get_valobj_sp_from_sbvalue, - SWIGPythonUpdateSynthProviderInstance swig_update_provider, - SWIGPythonMightHaveChildrenSynthProviderInstance swig_mighthavechildren_provider, - SWIGPythonGetValueSynthProviderInstance swig_getvalue_provider, - SWIGPythonCallCommand swig_call_command, - SWIGPythonCallModuleInit swig_call_module_init, - SWIGPythonCreateOSPlugin swig_create_os_plugin, - SWIGPythonScriptKeyword_Process swig_run_script_keyword_process, - SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread, - SWIGPythonScriptKeyword_Target swig_run_script_keyword_target, - SWIGPythonScriptKeyword_Frame swig_run_script_keyword_frame, - SWIGPythonScriptKeyword_Value swig_run_script_keyword_value, - SWIGPython_GetDynamicSetting swig_plugin_get, - SWIGPythonCreateScriptedThreadPlan swig_thread_plan_script, - SWIGPythonCallThreadPlan swig_call_thread_plan); - - const char * - GetDictionaryName () - { - return m_dictionary_name.c_str(); - } - - - PyThreadState * - GetThreadState() - { - return m_command_thread_state; - } - - void - SetThreadState (PyThreadState *s) - { - if (s) - m_command_thread_state = s; - } - - //---------------------------------------------------------------------- - // IOHandlerDelegate - //---------------------------------------------------------------------- - void - IOHandlerActivated (IOHandler &io_handler) override; - - void - IOHandlerInputComplete (IOHandler &io_handler, std::string &data) override; - -protected: - - bool - EnterSession (uint16_t on_entry_flags, - FILE *in, - FILE *out, - FILE *err); - - void - LeaveSession (); - - void - SaveTerminalState (int fd); - - void - RestoreTerminalState (); - - class SynchronicityHandler - { - private: - lldb::DebuggerSP m_debugger_sp; - ScriptedCommandSynchronicity m_synch_wanted; - bool m_old_asynch; - public: - SynchronicityHandler(lldb::DebuggerSP, - ScriptedCommandSynchronicity); - ~SynchronicityHandler(); - }; - - class ScriptInterpreterPythonObject : public ScriptInterpreterObject - { - public: - ScriptInterpreterPythonObject() : - ScriptInterpreterObject() - {} - - ScriptInterpreterPythonObject(void* obj) : - ScriptInterpreterObject(obj) - { - Py_XINCREF(m_object); - } - - explicit operator bool () - { - return m_object && m_object != Py_None; - } - - - virtual - ~ScriptInterpreterPythonObject() - { - if (Py_IsInitialized()) - Py_XDECREF(m_object); - m_object = NULL; - } - private: - DISALLOW_COPY_AND_ASSIGN (ScriptInterpreterPythonObject); - }; -public: - class Locker : public ScriptInterpreterLocker - { - public: - - enum OnEntry - { - AcquireLock = 0x0001, - InitSession = 0x0002, - InitGlobals = 0x0004, - NoSTDIN = 0x0008 - }; - - enum OnLeave - { - FreeLock = 0x0001, - FreeAcquiredLock = 0x0002, // do not free the lock if we already held it when calling constructor - TearDownSession = 0x0004 - }; - - Locker (ScriptInterpreterPython *py_interpreter = NULL, - uint16_t on_entry = AcquireLock | InitSession, - uint16_t on_leave = FreeLock | TearDownSession, - FILE *in = NULL, - FILE *out = NULL, - FILE *err = NULL); - - ~Locker (); - - private: - - bool - DoAcquireLock (); - - bool - DoInitSession (uint16_t on_entry_flags, FILE *in, FILE *out, FILE *err); - - bool - DoFreeLock (); - - bool - DoTearDownSession (); - - static void - ReleasePythonLock (); - - bool m_teardown_session; - ScriptInterpreterPython *m_python_interpreter; -// FILE* m_tmp_fh; - PyGILState_STATE m_GILState; - }; -protected: - - uint32_t - IsExecutingPython () const - { - return m_lock_count > 0; - } - - uint32_t - IncrementLockCount() - { - return ++m_lock_count; - } - - uint32_t - DecrementLockCount() - { - if (m_lock_count > 0) - --m_lock_count; - return m_lock_count; - } - - enum ActiveIOHandler { - eIOHandlerNone, - eIOHandlerBreakpoint, - eIOHandlerWatchpoint - }; - PythonObject & - GetMainModule (); - - PythonDictionary & - GetSessionDictionary (); - - PythonDictionary & - GetSysModuleDictionary (); - - bool - GetEmbeddedInterpreterModuleObjects (); - - PythonObject m_saved_stdin; - PythonObject m_saved_stdout; - PythonObject m_saved_stderr; - PythonObject m_main_module; - PythonObject m_lldb_module; - PythonDictionary m_session_dict; - PythonDictionary m_sys_module_dict; - PythonObject m_run_one_line_function; - PythonObject m_run_one_line_str_global; - std::string m_dictionary_name; - TerminalState m_terminal_state; - ActiveIOHandler m_active_io_handler; - bool m_session_is_active; - bool m_pty_slave_is_open; - bool m_valid_session; - uint32_t m_lock_count; - PyThreadState *m_command_thread_state; -}; -} // namespace lldb_private - -#endif // #ifdef LLDB_DISABLE_PYTHON - -#endif // #ifndef liblldb_ScriptInterpreterPython_h_ Index: include/lldb/ScriptInterpreter/Python/PythonDataObjects.h =================================================================== --- /dev/null +++ include/lldb/ScriptInterpreter/Python/PythonDataObjects.h @@ -0,0 +1,193 @@ +//===-- PythonDataObjects.h----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_PythonDataObjects_h_ +#define liblldb_PythonDataObjects_h_ + +// C Includes +// C++ Includes + +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-defines.h" +#include "lldb/Core/ConstString.h" +#include "lldb/Core/Flags.h" +#include "lldb/Interpreter/OptionValue.h" +#include "lldb/lldb-python.h" + +namespace lldb_private +{ + +class PythonObject +{ + public: + PythonObject() + : m_py_obj(NULL) + { + } + + explicit PythonObject(PyObject *py_obj) + : m_py_obj(NULL) + { + Reset(py_obj); + } + + PythonObject(const PythonObject &rhs) + : m_py_obj(NULL) + { + Reset(rhs.m_py_obj); + } + + explicit PythonObject(const lldb::ScriptInterpreterObjectSP &script_object_sp); + + virtual ~PythonObject() { Reset(NULL); } + + bool + Reset(const PythonObject &object) + { + return Reset(object.get()); + } + + virtual bool + Reset(PyObject *py_obj = NULL) + { + if (py_obj != m_py_obj) + { + if (Py_IsInitialized()) + Py_XDECREF(m_py_obj); + m_py_obj = py_obj; + if (Py_IsInitialized()) + Py_XINCREF(m_py_obj); + } + return true; + } + + void + Dump() const + { + if (m_py_obj) + _PyObject_Dump(m_py_obj); + else + puts("NULL"); + } + + void Dump(Stream &strm) const; + + PyObject * + get() const + { + return m_py_obj; + } + + PythonString Repr(); + + PythonString Str(); + + explicit operator bool() const { return m_py_obj != NULL; } + + bool IsNULLOrNone() const; + + protected: + PyObject *m_py_obj; +}; + +class PythonString : public PythonObject +{ + public: + PythonString(); + PythonString(PyObject *o); + PythonString(const PythonObject &object); + PythonString(const lldb::ScriptInterpreterObjectSP &script_object_sp); + PythonString(const char *string); + virtual ~PythonString(); + + virtual bool Reset(PyObject *py_obj = NULL); + + const char *GetString() const; + + size_t GetSize() const; + + void SetString(const char *string); +}; + +class PythonInteger : public PythonObject +{ + public: + PythonInteger(); + PythonInteger(PyObject *py_obj); + PythonInteger(const PythonObject &object); + PythonInteger(const lldb::ScriptInterpreterObjectSP &script_object_sp); + PythonInteger(int64_t value); + virtual ~PythonInteger(); + + virtual bool Reset(PyObject *py_obj = NULL); + + int64_t GetInteger(); + + void SetInteger(int64_t value); +}; + +class PythonList : public PythonObject +{ + public: + PythonList(bool create_empty); + PythonList(PyObject *py_obj); + PythonList(const PythonObject &object); + PythonList(const lldb::ScriptInterpreterObjectSP &script_object_sp); + PythonList(uint32_t count); + virtual ~PythonList(); + + virtual bool Reset(PyObject *py_obj = NULL); + + uint32_t GetSize(); + + PythonObject GetItemAtIndex(uint32_t index); + + void SetItemAtIndex(uint32_t index, const PythonObject &object); + + void AppendItem(const PythonObject &object); +}; + +class PythonDictionary : public PythonObject +{ + public: + explicit PythonDictionary(bool create_empty); + PythonDictionary(PyObject *object); + PythonDictionary(const PythonObject &object); + PythonDictionary(const lldb::ScriptInterpreterObjectSP &script_object_sp); + virtual ~PythonDictionary(); + + virtual bool Reset(PyObject *object = NULL); + + uint32_t GetSize(); + + PythonObject GetItemForKey(const PythonString &key) const; + + const char *GetItemForKeyAsString(const PythonString &key, const char *fail_value = NULL) const; + + int64_t GetItemForKeyAsInteger(const PythonString &key, int64_t fail_value = 0) const; + + PythonObject GetItemForKey(const char *key) const; + + typedef bool (*DictionaryIteratorCallback)(PythonString *key, PythonDictionary *dict); + + PythonList GetKeys() const; + + PythonString GetKeyAtPosition(uint32_t pos) const; + + PythonObject GetValueAtPosition(uint32_t pos) const; + + void SetItemForKey(const PythonString &key, PyObject *value); + + void SetItemForKey(const PythonString &key, const PythonObject &value); +}; + +} // namespace lldb_private + +#endif // liblldb_PythonDataObjects_h_ Index: include/lldb/ScriptInterpreter/Python/PythonPointer.h =================================================================== --- /dev/null +++ include/lldb/ScriptInterpreter/Python/PythonPointer.h @@ -0,0 +1,86 @@ +//===---------------------PythonPointer.h ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef utility_PythonPointer_h_ +#define utility_PythonPointer_h_ + +#include + +#include "lldb/lldb-python.h" + +namespace lldb_private +{ + +template class PythonPointer +{ + public: + typedef PyObject *element_type; + + private: + element_type *ptr_; + bool my_ref; + + public: + PythonPointer(element_type p, bool steal_ref = false) + : ptr_(p) + , my_ref(!steal_ref) + { + if (my_ref) + Py_INCREF(ptr_); + } + + PythonPointer(const PythonPointer &r, bool steal_ref = false) + : ptr_(r.ptr_) + , my_ref(!steal_ref) + { + if (my_ref) + Py_INCREF(ptr_); + } + + ~PythonPointer() + { + if (my_ref) + Py_XDECREF(ptr_); + } + + PythonPointer + StealReference() + { + return PythonPointer(ptr_, true); + } + + PythonPointer + DuplicateReference() + { + return PythonPointer(ptr_, false); + } + + element_type + get() const + { + return ptr_; + } + + bool + IsNull() + { + return ptr_ == NULL; + } + bool + IsNone() + { + return ptr_ == Py_None; + } + + operator PyObject *() { return ptr_; } +}; + +} // namespace lldb + +#endif // utility_PythonPointer_h_ Index: include/lldb/ScriptInterpreter/Python/ScriptInterpreterPython.h =================================================================== --- /dev/null +++ include/lldb/ScriptInterpreter/Python/ScriptInterpreterPython.h @@ -0,0 +1,356 @@ +//===-- ScriptInterpreterPython.h -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ScriptInterpreterPython_h_ +#define liblldb_ScriptInterpreterPython_h_ + +#ifdef LLDB_DISABLE_PYTHON + +// Python is disabled in this build + +#else + +#include "lldb/lldb-python.h" +#include "lldb/lldb-private.h" +#include "lldb/Core/IOHandler.h" +#include "lldb/ScriptInterpreter/ScriptInterpreter.h" +#include "lldb/ScriptInterpreter/Python/PythonDataObjects.h" +#include "lldb/Host/Terminal.h" + +class IOHandlerPythonInterpreter; + +namespace lldb_private +{ + +class ScriptInterpreterPython : public ScriptInterpreter, public IOHandlerDelegateMultiline +{ + public: + friend class IOHandlerPythonInterpreter; + + ScriptInterpreterPython(CommandInterpreter &interpreter); + + ~ScriptInterpreterPython(); + + bool Interrupt() override; + + bool ExecuteOneLine(const char *command, CommandReturnObject *result, + const ExecuteScriptOptions &options = ExecuteScriptOptions()) override; + + void ExecuteInterpreterLoop() override; + + bool ExecuteOneLineWithReturn(const char *in_string, ScriptInterpreter::ScriptReturnType return_type, void *ret_value, + const ExecuteScriptOptions &options = ExecuteScriptOptions()) override; + + lldb_private::Error ExecuteMultipleLines(const char *in_string, const ExecuteScriptOptions &options = ExecuteScriptOptions()) override; + + Error ExportFunctionDefinitionToInterpreter(StringList &function_def) override; + + bool GenerateTypeScriptFunction(StringList &input, std::string &output, const void *name_token = NULL) override; + + bool GenerateTypeSynthClass(StringList &input, std::string &output, const void *name_token = NULL) override; + + bool GenerateTypeSynthClass(const char *oneliner, std::string &output, const void *name_token = NULL) override; + + // use this if the function code is just a one-liner script + bool GenerateTypeScriptFunction(const char *oneliner, std::string &output, const void *name_token = NULL) override; + + bool GenerateScriptAliasFunction(StringList &input, std::string &output) override; + + lldb::ScriptInterpreterObjectSP CreateSyntheticScriptedProvider(const char *class_name, lldb::ValueObjectSP valobj) override; + + lldb::ScriptInterpreterObjectSP CreateScriptedThreadPlan(const char *class_name, lldb::ThreadPlanSP thread_plan) override; + + bool ScriptedThreadPlanExplainsStop(lldb::ScriptInterpreterObjectSP implementor_sp, Event *event, bool &script_error) override; + bool ScriptedThreadPlanShouldStop(lldb::ScriptInterpreterObjectSP implementor_sp, Event *event, bool &script_error) override; + lldb::StateType ScriptedThreadPlanGetRunState(lldb::ScriptInterpreterObjectSP implementor_sp, bool &script_error) override; + + lldb::ScriptInterpreterObjectSP OSPlugin_CreatePluginObject(const char *class_name, lldb::ProcessSP process_sp) override; + + lldb::ScriptInterpreterObjectSP OSPlugin_RegisterInfo(lldb::ScriptInterpreterObjectSP os_plugin_object_sp) override; + + lldb::ScriptInterpreterObjectSP OSPlugin_ThreadsInfo(lldb::ScriptInterpreterObjectSP os_plugin_object_sp) override; + + lldb::ScriptInterpreterObjectSP OSPlugin_RegisterContextData(lldb::ScriptInterpreterObjectSP os_plugin_object_sp, + lldb::tid_t thread_id) override; + + lldb::ScriptInterpreterObjectSP OSPlugin_CreateThread(lldb::ScriptInterpreterObjectSP os_plugin_object_sp, lldb::tid_t tid, + lldb::addr_t context) override; + + lldb::ScriptInterpreterObjectSP LoadPluginModule(const FileSpec &file_spec, lldb_private::Error &error) override; + + lldb::ScriptInterpreterObjectSP GetDynamicSettings(lldb::ScriptInterpreterObjectSP plugin_module_sp, Target *target, + const char *setting_name, lldb_private::Error &error) override; + + size_t CalculateNumChildren(const lldb::ScriptInterpreterObjectSP &implementor) override; + + lldb::ValueObjectSP GetChildAtIndex(const lldb::ScriptInterpreterObjectSP &implementor, uint32_t idx) override; + + int GetIndexOfChildWithName(const lldb::ScriptInterpreterObjectSP &implementor, const char *child_name) override; + + bool UpdateSynthProviderInstance(const lldb::ScriptInterpreterObjectSP &implementor) override; + + bool MightHaveChildrenSynthProviderInstance(const lldb::ScriptInterpreterObjectSP &implementor) override; + + lldb::ValueObjectSP GetSyntheticValue(const lldb::ScriptInterpreterObjectSP &implementor) override; + + bool RunScriptBasedCommand(const char *impl_function, const char *args, ScriptedCommandSynchronicity synchronicity, + lldb_private::CommandReturnObject &cmd_retobj, Error &error, + const lldb_private::ExecutionContext &exe_ctx) override; + + Error GenerateFunction(const char *signature, const StringList &input) override; + + Error GenerateBreakpointCommandCallbackData(StringList &input, std::string &output) override; + + bool GenerateWatchpointCommandCallbackData(StringList &input, std::string &output) override; + + // static size_t + // GenerateBreakpointOptionsCommandCallback (void *baton, + // InputReader &reader, + // lldb::InputReaderAction notification, + // const char *bytes, + // size_t bytes_len); + // + // static size_t + // GenerateWatchpointOptionsCommandCallback (void *baton, + // InputReader &reader, + // lldb::InputReaderAction notification, + // const char *bytes, + // size_t bytes_len); + + static bool BreakpointCallbackFunction(void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, + lldb::user_id_t break_loc_id); + + static bool WatchpointCallbackFunction(void *baton, StoppointCallbackContext *context, lldb::user_id_t watch_id); + + bool GetScriptedSummary(const char *function_name, lldb::ValueObjectSP valobj, lldb::ScriptInterpreterObjectSP &callee_wrapper_sp, + const TypeSummaryOptions &options, std::string &retval) override; + + void Clear() override; + + bool GetDocumentationForItem(const char *item, std::string &dest) override; + + bool + CheckObjectExists(const char *name) override + { + if (!name || !name[0]) + return false; + std::string temp; + return GetDocumentationForItem(name, temp); + } + + bool RunScriptFormatKeyword(const char *impl_function, Process *process, std::string &output, Error &error) override; + + bool RunScriptFormatKeyword(const char *impl_function, Thread *thread, std::string &output, Error &error) override; + + bool RunScriptFormatKeyword(const char *impl_function, Target *target, std::string &output, Error &error) override; + + bool RunScriptFormatKeyword(const char *impl_function, StackFrame *frame, std::string &output, Error &error) override; + + bool RunScriptFormatKeyword(const char *impl_function, ValueObject *value, std::string &output, Error &error) override; + + bool LoadScriptingModule(const char *filename, bool can_reload, bool init_session, lldb_private::Error &error, + lldb::ScriptInterpreterObjectSP *module_sp = nullptr) override; + + bool IsReservedWord(const char *word) override; + + lldb::ScriptInterpreterObjectSP MakeScriptObject(void *object) override; + + std::unique_ptr AcquireInterpreterLock() override; + + void CollectDataForBreakpointCommandCallback(std::vector &bp_options_vec, CommandReturnObject &result) override; + + void CollectDataForWatchpointCommandCallback(WatchpointOptions *wp_options, CommandReturnObject &result) override; + + /// Set the callback body text into the callback for the breakpoint. + Error SetBreakpointCommandCallback(BreakpointOptions *bp_options, const char *callback_body) override; + + void SetBreakpointCommandCallbackFunction(BreakpointOptions *bp_options, const char *function_name) override; + + /// Set a one-liner as the callback for the watchpoint. + void SetWatchpointCommandCallback(WatchpointOptions *wp_options, const char *oneliner) override; + + StringList ReadCommandInputFromUser(FILE *in_file); + + virtual void ResetOutputFileHandle(FILE *new_fh) override; + + static void InitializePrivate(); + + const char * + GetDictionaryName() + { + return m_dictionary_name.c_str(); + } + + PyThreadState * + GetThreadState() + { + return m_command_thread_state; + } + + void + SetThreadState(PyThreadState *s) + { + if (s) + m_command_thread_state = s; + } + + //---------------------------------------------------------------------- + // IOHandlerDelegate + //---------------------------------------------------------------------- + void IOHandlerActivated(IOHandler &io_handler) override; + + void IOHandlerInputComplete(IOHandler &io_handler, std::string &data) override; + + protected: + bool EnterSession(uint16_t on_entry_flags, FILE *in, FILE *out, FILE *err); + + void LeaveSession(); + + void SaveTerminalState(int fd); + + void RestoreTerminalState(); + + class SynchronicityHandler + { + private: + lldb::DebuggerSP m_debugger_sp; + ScriptedCommandSynchronicity m_synch_wanted; + bool m_old_asynch; + + public: + SynchronicityHandler(lldb::DebuggerSP, ScriptedCommandSynchronicity); + ~SynchronicityHandler(); + }; + + class ScriptInterpreterPythonObject : public ScriptInterpreterObject + { + public: + ScriptInterpreterPythonObject() + : ScriptInterpreterObject() + { + } + + ScriptInterpreterPythonObject(void *obj) + : ScriptInterpreterObject(obj) + { + Py_XINCREF(m_object); + } + + explicit operator bool() { return m_object && m_object != Py_None; } + + virtual ~ScriptInterpreterPythonObject() + { + if (Py_IsInitialized()) + Py_XDECREF(m_object); + m_object = NULL; + } + + private: + DISALLOW_COPY_AND_ASSIGN(ScriptInterpreterPythonObject); + }; + + public: + class Locker : public ScriptInterpreterLocker + { + public: + enum OnEntry + { + AcquireLock = 0x0001, + InitSession = 0x0002, + InitGlobals = 0x0004, + NoSTDIN = 0x0008 + }; + + enum OnLeave + { + FreeLock = 0x0001, + FreeAcquiredLock = 0x0002, // do not free the lock if we already held it when calling constructor + TearDownSession = 0x0004 + }; + + Locker(ScriptInterpreterPython *py_interpreter = NULL, uint16_t on_entry = AcquireLock | InitSession, + uint16_t on_leave = FreeLock | TearDownSession, FILE *in = NULL, FILE *out = NULL, FILE *err = NULL); + + ~Locker(); + + private: + bool DoAcquireLock(); + + bool DoInitSession(uint16_t on_entry_flags, FILE *in, FILE *out, FILE *err); + + bool DoFreeLock(); + + bool DoTearDownSession(); + + static void ReleasePythonLock(); + + bool m_teardown_session; + ScriptInterpreterPython *m_python_interpreter; + // FILE* m_tmp_fh; + PyGILState_STATE m_GILState; + }; + + protected: + uint32_t + IsExecutingPython() const + { + return m_lock_count > 0; + } + + uint32_t + IncrementLockCount() + { + return ++m_lock_count; + } + + uint32_t + DecrementLockCount() + { + if (m_lock_count > 0) + --m_lock_count; + return m_lock_count; + } + + enum ActiveIOHandler + { + eIOHandlerNone, + eIOHandlerBreakpoint, + eIOHandlerWatchpoint + }; + PythonObject &GetMainModule(); + + PythonDictionary &GetSessionDictionary(); + + PythonDictionary &GetSysModuleDictionary(); + + bool GetEmbeddedInterpreterModuleObjects(); + + PythonObject m_saved_stdin; + PythonObject m_saved_stdout; + PythonObject m_saved_stderr; + PythonObject m_main_module; + PythonObject m_lldb_module; + PythonDictionary m_session_dict; + PythonDictionary m_sys_module_dict; + PythonObject m_run_one_line_function; + PythonObject m_run_one_line_str_global; + std::string m_dictionary_name; + TerminalState m_terminal_state; + ActiveIOHandler m_active_io_handler; + bool m_session_is_active; + bool m_pty_slave_is_open; + bool m_valid_session; + uint32_t m_lock_count; + PyThreadState *m_command_thread_state; +}; +} // namespace lldb_private + +#endif // #ifdef LLDB_DISABLE_PYTHON + +#endif // #ifndef liblldb_ScriptInterpreterPython_h_ Index: include/lldb/ScriptInterpreter/ScriptInterpreter.h =================================================================== --- /dev/null +++ include/lldb/ScriptInterpreter/ScriptInterpreter.h @@ -0,0 +1,500 @@ +//===-- ScriptInterpreter.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ScriptInterpreter_h_ +#define liblldb_ScriptInterpreter_h_ + +#include "lldb/lldb-private.h" + +#include "lldb/Core/Broadcaster.h" +#include "lldb/Core/Error.h" + +#include "lldb/Utility/PseudoTerminal.h" + +namespace lldb_private +{ + +class ScriptInterpreterObject +{ + public: + ScriptInterpreterObject() + : m_object(NULL) + { + } + + ScriptInterpreterObject(void *obj) + : m_object(obj) + { + } + + ScriptInterpreterObject(const ScriptInterpreterObject &rhs) + : m_object(rhs.m_object) + { + } + + virtual void *GetObject() + { + return m_object; + } + + explicit operator bool () + { + return m_object != NULL; + } + + ScriptInterpreterObject &operator=(const ScriptInterpreterObject &rhs) + { + if (this != &rhs) + m_object = rhs.m_object; + return *this; + } + + virtual ~ScriptInterpreterObject() {} + + protected: + void *m_object; +}; + +class ScriptInterpreterLocker +{ + public: + ScriptInterpreterLocker() {} + + virtual ~ScriptInterpreterLocker() {} + + private: + DISALLOW_COPY_AND_ASSIGN(ScriptInterpreterLocker); +}; + +class ScriptInterpreter +{ + public: + typedef enum + { + eScriptReturnTypeCharPtr, + eScriptReturnTypeBool, + eScriptReturnTypeShortInt, + eScriptReturnTypeShortIntUnsigned, + eScriptReturnTypeInt, + eScriptReturnTypeIntUnsigned, + eScriptReturnTypeLongInt, + eScriptReturnTypeLongIntUnsigned, + eScriptReturnTypeLongLong, + eScriptReturnTypeLongLongUnsigned, + eScriptReturnTypeFloat, + eScriptReturnTypeDouble, + eScriptReturnTypeChar, + eScriptReturnTypeCharStrOrNone, + eScriptReturnTypeOpaqueObject + } ScriptReturnType; + + ScriptInterpreter(CommandInterpreter &interpreter, lldb::ScriptLanguage script_lang); + + virtual ~ScriptInterpreter(); + + struct ExecuteScriptOptions + { + public: + ExecuteScriptOptions() + : m_enable_io(true) + , m_set_lldb_globals(true) + , m_maskout_errors(true) + { + } + + bool + GetEnableIO() const + { + return m_enable_io; + } + + bool + GetSetLLDBGlobals() const + { + return m_set_lldb_globals; + } + + bool + GetMaskoutErrors() const + { + return m_maskout_errors; + } + + ExecuteScriptOptions & + SetEnableIO(bool enable) + { + m_enable_io = enable; + return *this; + } + + ExecuteScriptOptions & + SetSetLLDBGlobals(bool set) + { + m_set_lldb_globals = set; + return *this; + } + + ExecuteScriptOptions & + SetMaskoutErrors(bool maskout) + { + m_maskout_errors = maskout; + return *this; + } + + private: + bool m_enable_io; + bool m_set_lldb_globals; + bool m_maskout_errors; + }; + + virtual bool + Interrupt() + { + return false; + } + + virtual bool ExecuteOneLine(const char *command, CommandReturnObject *result, + const ExecuteScriptOptions &options = ExecuteScriptOptions()) = 0; + + virtual void ExecuteInterpreterLoop() = 0; + + virtual bool + ExecuteOneLineWithReturn(const char *in_string, ScriptReturnType return_type, void *ret_value, + const ExecuteScriptOptions &options = ExecuteScriptOptions()) + { + return true; + } + + virtual Error + ExecuteMultipleLines(const char *in_string, const ExecuteScriptOptions &options = ExecuteScriptOptions()) + { + Error error; + error.SetErrorString("not implemented"); + return error; + } + + virtual Error + ExportFunctionDefinitionToInterpreter(StringList &function_def) + { + Error error; + error.SetErrorString("not implemented"); + return error; + } + + virtual Error + GenerateBreakpointCommandCallbackData(StringList &input, std::string &output) + { + Error error; + error.SetErrorString("not implemented"); + return error; + } + + virtual bool + GenerateWatchpointCommandCallbackData(StringList &input, std::string &output) + { + return false; + } + + virtual bool + GenerateTypeScriptFunction(const char *oneliner, std::string &output, const void *name_token = NULL) + { + return false; + } + + virtual bool + GenerateTypeScriptFunction(StringList &input, std::string &output, const void *name_token = NULL) + { + return false; + } + + virtual bool + GenerateScriptAliasFunction(StringList &input, std::string &output) + { + return false; + } + + virtual bool + GenerateTypeSynthClass(StringList &input, std::string &output, const void *name_token = NULL) + { + return false; + } + + virtual bool + GenerateTypeSynthClass(const char *oneliner, std::string &output, const void *name_token = NULL) + { + return false; + } + + virtual lldb::ScriptInterpreterObjectSP + CreateSyntheticScriptedProvider(const char *class_name, lldb::ValueObjectSP valobj) + { + return lldb::ScriptInterpreterObjectSP(); + } + + virtual lldb::ScriptInterpreterObjectSP + OSPlugin_CreatePluginObject(const char *class_name, lldb::ProcessSP process_sp) + { + return lldb::ScriptInterpreterObjectSP(); + } + + virtual lldb::ScriptInterpreterObjectSP + OSPlugin_RegisterInfo(lldb::ScriptInterpreterObjectSP os_plugin_object_sp) + { + return lldb::ScriptInterpreterObjectSP(); + } + + virtual lldb::ScriptInterpreterObjectSP + OSPlugin_ThreadsInfo(lldb::ScriptInterpreterObjectSP os_plugin_object_sp) + { + return lldb::ScriptInterpreterObjectSP(); + } + + virtual lldb::ScriptInterpreterObjectSP + OSPlugin_RegisterContextData(lldb::ScriptInterpreterObjectSP os_plugin_object_sp, lldb::tid_t thread_id) + { + return lldb::ScriptInterpreterObjectSP(); + } + + virtual lldb::ScriptInterpreterObjectSP + OSPlugin_CreateThread(lldb::ScriptInterpreterObjectSP os_plugin_object_sp, lldb::tid_t tid, lldb::addr_t context) + { + return lldb::ScriptInterpreterObjectSP(); + } + + virtual lldb::ScriptInterpreterObjectSP + CreateScriptedThreadPlan(const char *class_name, lldb::ThreadPlanSP thread_plan_sp) + { + return lldb::ScriptInterpreterObjectSP(); + } + + virtual bool + ScriptedThreadPlanExplainsStop(lldb::ScriptInterpreterObjectSP implementor_sp, Event *event, bool &script_error) + { + script_error = true; + return true; + } + + virtual bool + ScriptedThreadPlanShouldStop(lldb::ScriptInterpreterObjectSP implementor_sp, Event *event, bool &script_error) + { + script_error = true; + return true; + } + + virtual lldb::StateType + ScriptedThreadPlanGetRunState(lldb::ScriptInterpreterObjectSP implementor_sp, bool &script_error) + { + script_error = true; + return lldb::eStateStepping; + } + + virtual lldb::ScriptInterpreterObjectSP + LoadPluginModule(const FileSpec &file_spec, lldb_private::Error &error) + { + return lldb::ScriptInterpreterObjectSP(); + } + + virtual lldb::ScriptInterpreterObjectSP + GetDynamicSettings(lldb::ScriptInterpreterObjectSP plugin_module_sp, Target *target, const char *setting_name, + lldb_private::Error &error) + { + return lldb::ScriptInterpreterObjectSP(); + } + + virtual Error + GenerateFunction(const char *signature, const StringList &input) + { + Error error; + error.SetErrorString("unimplemented"); + return error; + } + + virtual void CollectDataForBreakpointCommandCallback(std::vector &options, CommandReturnObject &result); + + virtual void CollectDataForWatchpointCommandCallback(WatchpointOptions *wp_options, CommandReturnObject &result); + + /// Set the specified text as the callback for the breakpoint. + Error SetBreakpointCommandCallback(std::vector &bp_options_vec, const char *callback_text); + + virtual Error + SetBreakpointCommandCallback(BreakpointOptions *bp_options, const char *callback_text) + { + Error error; + error.SetErrorString("unimplemented"); + return error; + } + + void SetBreakpointCommandCallbackFunction(std::vector &bp_options_vec, const char *function_name); + + /// Set a one-liner as the callback for the breakpoint. + virtual void + SetBreakpointCommandCallbackFunction(BreakpointOptions *bp_options, const char *function_name) + { + return; + } + + /// Set a one-liner as the callback for the watchpoint. + virtual void + SetWatchpointCommandCallback(WatchpointOptions *wp_options, const char *oneliner) + { + return; + } + + virtual bool + GetScriptedSummary(const char *function_name, lldb::ValueObjectSP valobj, lldb::ScriptInterpreterObjectSP &callee_wrapper_sp, + const TypeSummaryOptions &options, std::string &retval) + { + return false; + } + + virtual void + Clear() + { + // Clean up any ref counts to SBObjects that might be in global variables + } + + virtual size_t + CalculateNumChildren(const lldb::ScriptInterpreterObjectSP &implementor) + { + return 0; + } + + virtual lldb::ValueObjectSP + GetChildAtIndex(const lldb::ScriptInterpreterObjectSP &implementor, uint32_t idx) + { + return lldb::ValueObjectSP(); + } + + virtual int + GetIndexOfChildWithName(const lldb::ScriptInterpreterObjectSP &implementor, const char *child_name) + { + return UINT32_MAX; + } + + virtual bool + UpdateSynthProviderInstance(const lldb::ScriptInterpreterObjectSP &implementor) + { + return false; + } + + virtual bool + MightHaveChildrenSynthProviderInstance(const lldb::ScriptInterpreterObjectSP &implementor) + { + return true; + } + + virtual lldb::ValueObjectSP + GetSyntheticValue(const lldb::ScriptInterpreterObjectSP &implementor) + { + return nullptr; + } + + virtual bool + RunScriptBasedCommand(const char *impl_function, const char *args, ScriptedCommandSynchronicity synchronicity, + lldb_private::CommandReturnObject &cmd_retobj, Error &error, const lldb_private::ExecutionContext &exe_ctx) + { + return false; + } + + virtual bool + RunScriptFormatKeyword(const char *impl_function, Process *process, std::string &output, Error &error) + { + error.SetErrorString("unimplemented"); + return false; + } + + virtual bool + RunScriptFormatKeyword(const char *impl_function, Thread *thread, std::string &output, Error &error) + { + error.SetErrorString("unimplemented"); + return false; + } + + virtual bool + RunScriptFormatKeyword(const char *impl_function, Target *target, std::string &output, Error &error) + { + error.SetErrorString("unimplemented"); + return false; + } + + virtual bool + RunScriptFormatKeyword(const char *impl_function, StackFrame *frame, std::string &output, Error &error) + { + error.SetErrorString("unimplemented"); + return false; + } + + virtual bool + RunScriptFormatKeyword(const char *impl_function, ValueObject *value, std::string &output, Error &error) + { + error.SetErrorString("unimplemented"); + return false; + } + + virtual bool + GetDocumentationForItem(const char *item, std::string &dest) + { + dest.clear(); + return false; + } + + virtual bool + CheckObjectExists(const char *name) + { + return false; + } + + virtual bool + LoadScriptingModule(const char *filename, bool can_reload, bool init_session, lldb_private::Error &error, + lldb::ScriptInterpreterObjectSP *module_sp = nullptr) + { + error.SetErrorString("loading unimplemented"); + return false; + } + + virtual bool + IsReservedWord (const char* word) + { + return false; + } + + virtual lldb::ScriptInterpreterObjectSP + MakeScriptObject(void *object) + { + return lldb::ScriptInterpreterObjectSP(new ScriptInterpreterObject(object)); + } + + virtual std::unique_ptr AcquireInterpreterLock(); + + const char *GetScriptInterpreterPtyName(); + + int GetMasterFileDescriptor(); + + CommandInterpreter &GetCommandInterpreter(); + + static std::string LanguageToString(lldb::ScriptLanguage language); + + virtual void + ResetOutputFileHandle(FILE *new_fh) + { + } // By default, do nothing. + + static ScriptInterpreter *GetScriptInterpreter(lldb::ScriptLanguage script_lang, CommandInterpreter &command_interpreter, + bool can_create); + + static void InitializePrivate(); + + protected: + CommandInterpreter &m_interpreter; + lldb::ScriptLanguage m_script_lang; +}; + +} // namespace lldb_private + +#endif // #ifndef liblldb_ScriptInterpreter_h_ Index: include/lldb/ScriptInterpreter/ScriptInterpreterNone.h =================================================================== --- /dev/null +++ include/lldb/ScriptInterpreter/ScriptInterpreterNone.h @@ -0,0 +1,32 @@ +//===-- ScriptInterpreterNone.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ScriptInterpreterNone_h_ +#define liblldb_ScriptInterpreterNone_h_ + +#include "lldb/ScriptInterpreter/ScriptInterpreter.h" + +namespace lldb_private +{ + +class ScriptInterpreterNone : public ScriptInterpreter +{ + public: + ScriptInterpreterNone(CommandInterpreter &interpreter); + + ~ScriptInterpreterNone(); + + bool ExecuteOneLine(const char *command, CommandReturnObject *result, const ExecuteScriptOptions &options = ExecuteScriptOptions()); + + void ExecuteInterpreterLoop(); +}; + +} // namespace lldb_private + +#endif // #ifndef liblldb_ScriptInterpreterNone_h_ Index: include/lldb/Utility/PythonPointer.h =================================================================== --- include/lldb/Utility/PythonPointer.h +++ /dev/null @@ -1,73 +0,0 @@ -//===---------------------PythonPointer.h ------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef utility_PythonPointer_h_ -#define utility_PythonPointer_h_ - -#include - -#include "lldb/lldb-python.h" - -namespace lldb_private { - -template -class PythonPointer -{ -public: - typedef PyObject* element_type; -private: - element_type* ptr_; - bool my_ref; -public: - - PythonPointer(element_type p, bool steal_ref = false) : - ptr_(p), - my_ref(!steal_ref) - { - if (my_ref) - Py_INCREF(ptr_); - } - - PythonPointer(const PythonPointer& r, bool steal_ref = false) : - ptr_(r.ptr_), - my_ref(!steal_ref) - { - if (my_ref) - Py_INCREF(ptr_); - } - - ~PythonPointer() - { - if (my_ref) - Py_XDECREF(ptr_); - } - - PythonPointer - StealReference() - { - return PythonPointer(ptr_,true); - } - - PythonPointer - DuplicateReference() - { - return PythonPointer(ptr_, false); - } - - element_type get() const {return ptr_;} - - bool IsNull() { return ptr_ == NULL; } - bool IsNone() { return ptr_ == Py_None; } - - operator PyObject* () { return ptr_; } -}; - -} // namespace lldb - -#endif // utility_PythonPointer_h_ Index: include/lldb/lldb-forward.h =================================================================== --- include/lldb/lldb-forward.h +++ include/lldb/lldb-forward.h @@ -184,7 +184,6 @@ class ScriptInterpreterLocker; class ScriptInterpreterObject; #ifndef LLDB_DISABLE_PYTHON -class ScriptInterpreterPython; struct ScriptSummaryFormat; #endif class SearchFilter; @@ -364,6 +363,7 @@ typedef std::shared_ptr QueueSP; typedef std::weak_ptr QueueWP; typedef std::shared_ptr QueueItemSP; + typedef std::shared_ptr ScriptInterpreterUP; typedef std::shared_ptr ScriptInterpreterObjectSP; #ifndef LLDB_DISABLE_PYTHON typedef std::shared_ptr ScriptSummaryFormatSP; Index: source/API/SBBreakpoint.cpp =================================================================== --- source/API/SBBreakpoint.cpp +++ source/API/SBBreakpoint.cpp @@ -25,7 +25,7 @@ #include "lldb/Core/Stream.h" #include "lldb/Core/StreamFile.h" #include "lldb/Interpreter/CommandInterpreter.h" -#include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/ScriptInterpreter/ScriptInterpreter.h" #include "lldb/Target/Process.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" Index: source/API/SBBreakpointLocation.cpp =================================================================== --- source/API/SBBreakpointLocation.cpp +++ source/API/SBBreakpointLocation.cpp @@ -22,7 +22,7 @@ #include "lldb/Core/Stream.h" #include "lldb/Core/StreamFile.h" #include "lldb/Interpreter/CommandInterpreter.h" -#include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/ScriptInterpreter/ScriptInterpreter.h" #include "lldb/Target/ThreadSpec.h" #include "lldb/Target/Target.h" #include "lldb/Target/ThreadSpec.h" Index: source/API/SBCommandInterpreter.cpp =================================================================== --- source/API/SBCommandInterpreter.cpp +++ source/API/SBCommandInterpreter.cpp @@ -566,170 +566,6 @@ return false; } -#ifndef LLDB_DISABLE_PYTHON - -// Defined in the SWIG source file -extern "C" void -init_lldb(void); - -// these are the Pythonic implementations of the required callbacks -// these are scripting-language specific, which is why they belong here -// we still need to use function pointers to them instead of relying -// on linkage-time resolution because the SWIG stuff and this file -// get built at different times -extern "C" bool -LLDBSwigPythonBreakpointCallbackFunction (const char *python_function_name, - const char *session_dictionary_name, - const lldb::StackFrameSP& sb_frame, - const lldb::BreakpointLocationSP& sb_bp_loc); - -extern "C" bool -LLDBSwigPythonWatchpointCallbackFunction (const char *python_function_name, - const char *session_dictionary_name, - const lldb::StackFrameSP& sb_frame, - const lldb::WatchpointSP& sb_wp); - -extern "C" bool -LLDBSwigPythonCallTypeScript (const char *python_function_name, - void *session_dictionary, - const lldb::ValueObjectSP& valobj_sp, - void** pyfunct_wrapper, - const lldb::TypeSummaryOptionsSP& options_sp, - std::string& retval); - -extern "C" void* -LLDBSwigPythonCreateSyntheticProvider (const char *python_class_name, - const char *session_dictionary_name, - const lldb::ValueObjectSP& valobj_sp); - - -extern "C" void* -LLDBSwigPythonCreateScriptedThreadPlan (const char *python_class_name, - const char *session_dictionary_name, - const lldb::ThreadPlanSP& thread_plan_sp); - -extern "C" bool -LLDBSWIGPythonCallThreadPlan (void *implementor, - const char *method_name, - Event *event_sp, - bool &got_error); - -extern "C" uint32_t -LLDBSwigPython_CalculateNumChildren (void *implementor); - -extern "C" void * -LLDBSwigPython_GetChildAtIndex (void *implementor, uint32_t idx); - -extern "C" int -LLDBSwigPython_GetIndexOfChildWithName (void *implementor, const char* child_name); - -extern "C" void * -LLDBSWIGPython_CastPyObjectToSBValue (void* data); - -extern lldb::ValueObjectSP -LLDBSWIGPython_GetValueObjectSPFromSBValue (void* data); - -extern "C" bool -LLDBSwigPython_UpdateSynthProviderInstance (void* implementor); - -extern "C" bool -LLDBSwigPython_MightHaveChildrenSynthProviderInstance (void* implementor); - -extern "C" void * -LLDBSwigPython_GetValueSynthProviderInstance (void* implementor); - -extern "C" bool -LLDBSwigPythonCallCommand (const char *python_function_name, - const char *session_dictionary_name, - lldb::DebuggerSP& debugger, - const char* args, - lldb_private::CommandReturnObject &cmd_retobj, - lldb::ExecutionContextRefSP exe_ctx_ref_sp); - -extern "C" bool -LLDBSwigPythonCallModuleInit (const char *python_module_name, - const char *session_dictionary_name, - lldb::DebuggerSP& debugger); - -extern "C" void* -LLDBSWIGPythonCreateOSPlugin (const char *python_class_name, - const char *session_dictionary_name, - const lldb::ProcessSP& process_sp); - -extern "C" bool -LLDBSWIGPythonRunScriptKeywordProcess (const char* python_function_name, - const char* session_dictionary_name, - lldb::ProcessSP& process, - std::string& output); - -extern "C" bool -LLDBSWIGPythonRunScriptKeywordThread (const char* python_function_name, - const char* session_dictionary_name, - lldb::ThreadSP& thread, - std::string& output); - -extern "C" bool -LLDBSWIGPythonRunScriptKeywordTarget (const char* python_function_name, - const char* session_dictionary_name, - lldb::TargetSP& target, - std::string& output); - -extern "C" bool -LLDBSWIGPythonRunScriptKeywordFrame (const char* python_function_name, - const char* session_dictionary_name, - lldb::StackFrameSP& frame, - std::string& output); - -extern "C" bool -LLDBSWIGPythonRunScriptKeywordValue (const char* python_function_name, - const char* session_dictionary_name, - lldb::ValueObjectSP& value, - std::string& output); - -extern "C" void* -LLDBSWIGPython_GetDynamicSetting (void* module, - const char* setting, - const lldb::TargetSP& target_sp); - - -#endif - -void -SBCommandInterpreter::InitializeSWIG () -{ - static bool g_initialized = false; - if (!g_initialized) - { - g_initialized = true; -#ifndef LLDB_DISABLE_PYTHON - ScriptInterpreter::InitializeInterpreter (init_lldb, - LLDBSwigPythonBreakpointCallbackFunction, - LLDBSwigPythonWatchpointCallbackFunction, - LLDBSwigPythonCallTypeScript, - LLDBSwigPythonCreateSyntheticProvider, - LLDBSwigPython_CalculateNumChildren, - LLDBSwigPython_GetChildAtIndex, - LLDBSwigPython_GetIndexOfChildWithName, - LLDBSWIGPython_CastPyObjectToSBValue, - LLDBSWIGPython_GetValueObjectSPFromSBValue, - LLDBSwigPython_UpdateSynthProviderInstance, - LLDBSwigPython_MightHaveChildrenSynthProviderInstance, - LLDBSwigPython_GetValueSynthProviderInstance, - LLDBSwigPythonCallCommand, - LLDBSwigPythonCallModuleInit, - LLDBSWIGPythonCreateOSPlugin, - LLDBSWIGPythonRunScriptKeywordProcess, - LLDBSWIGPythonRunScriptKeywordThread, - LLDBSWIGPythonRunScriptKeywordTarget, - LLDBSWIGPythonRunScriptKeywordFrame, - LLDBSWIGPythonRunScriptKeywordValue, - LLDBSWIGPython_GetDynamicSetting, - LLDBSwigPythonCreateScriptedThreadPlan, - LLDBSWIGPythonCallThreadPlan); -#endif - } -} - lldb::SBCommand SBCommandInterpreter::AddMultiwordCommand (const char* name, const char* help) { Index: source/API/SBDebugger.cpp =================================================================== --- source/API/SBDebugger.cpp +++ source/API/SBDebugger.cpp @@ -115,8 +115,6 @@ if (log) log->Printf ("SBDebugger::Initialize ()"); - SBCommandInterpreter::InitializeSWIG (); - Debugger::Initialize(LoadPlugin); } Index: source/API/SBTypeCategory.cpp =================================================================== --- source/API/SBTypeCategory.cpp +++ source/API/SBTypeCategory.cpp @@ -21,7 +21,7 @@ #include "lldb/Core/Debugger.h" #include "lldb/DataFormatters/DataVisualization.h" #include "lldb/Interpreter/CommandInterpreter.h" -#include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/ScriptInterpreter/ScriptInterpreter.h" using namespace lldb; using namespace lldb_private; Index: source/CMakeLists.txt =================================================================== --- source/CMakeLists.txt +++ source/CMakeLists.txt @@ -34,6 +34,7 @@ add_subdirectory(Host) add_subdirectory(Interpreter) add_subdirectory(Plugins) +add_subdirectory(ScriptInterpreter) add_subdirectory(Symbol) add_subdirectory(Target) add_subdirectory(Utility) Index: source/Commands/CommandObjectCommands.cpp =================================================================== --- source/Commands/CommandObjectCommands.cpp +++ source/Commands/CommandObjectCommands.cpp @@ -28,8 +28,7 @@ #include "lldb/Interpreter/OptionValueBoolean.h" #include "lldb/Interpreter/OptionValueUInt64.h" #include "lldb/Interpreter/Options.h" -#include "lldb/Interpreter/ScriptInterpreter.h" -#include "lldb/Interpreter/ScriptInterpreterPython.h" +#include "lldb/ScriptInterpreter/ScriptInterpreter.h" using namespace lldb; using namespace lldb_private; Index: source/Core/Module.cpp =================================================================== --- source/Core/Module.cpp +++ source/Core/Module.cpp @@ -24,7 +24,7 @@ #include "lldb/Host/Host.h" #include "lldb/Host/Symbols.h" #include "lldb/Interpreter/CommandInterpreter.h" -#include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/ScriptInterpreter/ScriptInterpreter.h" #include "lldb/lldb-private-log.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/ObjectFile.h" Index: source/Core/ValueObject.cpp =================================================================== --- source/Core/ValueObject.cpp +++ source/Core/ValueObject.cpp @@ -43,7 +43,6 @@ #include "lldb/Host/Endian.h" #include "lldb/Interpreter/CommandInterpreter.h" -#include "lldb/Interpreter/ScriptInterpreterPython.h" #include "lldb/Symbol/ClangASTType.h" #include "lldb/Symbol/ClangASTContext.h" Index: source/DataFormatters/FormatManager.cpp =================================================================== --- source/DataFormatters/FormatManager.cpp +++ source/DataFormatters/FormatManager.cpp @@ -18,7 +18,6 @@ #include "lldb/Core/Debugger.h" #include "lldb/DataFormatters/CXXFormatterFunctions.h" -#include "lldb/Interpreter/ScriptInterpreterPython.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Platform.h" #include "llvm/ADT/STLExtras.h" Index: source/DataFormatters/TypeSynthetic.cpp =================================================================== --- source/DataFormatters/TypeSynthetic.cpp +++ source/DataFormatters/TypeSynthetic.cpp @@ -23,7 +23,9 @@ #include "lldb/Core/StreamString.h" #include "lldb/DataFormatters/TypeSynthetic.h" #include "lldb/Interpreter/CommandInterpreter.h" -#include "lldb/Interpreter/ScriptInterpreterPython.h" +#ifndef LLDB_DISABLE_PYTHON +#include "lldb/ScriptInterpreter/Python/ScriptInterpreterPython.h" +#endif #include "lldb/Symbol/ClangASTType.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" Index: source/Interpreter/CMakeLists.txt =================================================================== --- source/Interpreter/CMakeLists.txt +++ source/Interpreter/CMakeLists.txt @@ -43,8 +43,4 @@ OptionGroupWatchpoint.cpp Options.cpp Property.cpp - PythonDataObjects.cpp - ScriptInterpreter.cpp - ScriptInterpreterNone.cpp - ScriptInterpreterPython.cpp ) Index: source/Interpreter/CommandInterpreter.cpp =================================================================== --- source/Interpreter/CommandInterpreter.cpp +++ source/Interpreter/CommandInterpreter.cpp @@ -60,8 +60,6 @@ #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/Options.h" -#include "lldb/Interpreter/ScriptInterpreterNone.h" -#include "lldb/Interpreter/ScriptInterpreterPython.h" #include "lldb/Target/Process.h" @@ -2850,42 +2848,8 @@ ScriptInterpreter * CommandInterpreter::GetScriptInterpreter (bool can_create) { - if (m_script_interpreter_ap.get() != nullptr) - return m_script_interpreter_ap.get(); - - if (!can_create) - return nullptr; - - // - // we need to protect the initialization of the script interpreter - // otherwise we could end up with two threads both trying to create - // their instance of it, and for some languages (e.g. Python) - // this is a bulletproof recipe for disaster! - // this needs to be a function-level static because multiple Debugger instances living in the same process - // still need to be isolated and not try to initialize Python concurrently - static Mutex g_interpreter_mutex(Mutex::eMutexTypeRecursive); - Mutex::Locker interpreter_lock(g_interpreter_mutex); - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); - if (log) - log->Printf("Initializing the ScriptInterpreter now\n"); - lldb::ScriptLanguage script_lang = GetDebugger().GetScriptLanguage(); - switch (script_lang) - { - case eScriptLanguagePython: -#ifndef LLDB_DISABLE_PYTHON - m_script_interpreter_ap.reset (new ScriptInterpreterPython (*this)); - break; -#else - // Fall through to the None case when python is disabled -#endif - case eScriptLanguageNone: - m_script_interpreter_ap.reset (new ScriptInterpreterNone (*this)); - break; - }; - - return m_script_interpreter_ap.get(); + return ScriptInterpreter::GetScriptInterpreter(script_lang, *this, can_create); } Index: source/Interpreter/CommandObject.cpp =================================================================== --- source/Interpreter/CommandObject.cpp +++ source/Interpreter/CommandObject.cpp @@ -30,8 +30,6 @@ #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" -#include "lldb/Interpreter/ScriptInterpreter.h" -#include "lldb/Interpreter/ScriptInterpreterPython.h" using namespace lldb; using namespace lldb_private; Index: source/Interpreter/CommandObjectScript.cpp =================================================================== --- source/Interpreter/CommandObjectScript.cpp +++ source/Interpreter/CommandObjectScript.cpp @@ -23,7 +23,7 @@ #include "lldb/Interpreter/Args.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" -#include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/ScriptInterpreter/ScriptInterpreter.h" using namespace lldb; using namespace lldb_private; Index: source/Interpreter/PythonDataObjects.cpp =================================================================== --- source/Interpreter/PythonDataObjects.cpp +++ /dev/null @@ -1,463 +0,0 @@ -//===-- PythonDataObjects.cpp ------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// In order to guarantee correct working with Python, Python.h *MUST* be -// the *FIRST* header file included here. -#ifdef LLDB_DISABLE_PYTHON - -// Python is disabled in this build - -#else - -#include "lldb/lldb-python.h" - -#include - -#include "lldb/Core/Stream.h" -#include "lldb/Host/File.h" -#include "lldb/Interpreter/PythonDataObjects.h" -#include "lldb/Interpreter/ScriptInterpreter.h" - -using namespace lldb_private; -using namespace lldb; - -//---------------------------------------------------------------------- -// PythonObject -//---------------------------------------------------------------------- -PythonObject::PythonObject (const lldb::ScriptInterpreterObjectSP &script_object_sp) : - m_py_obj (nullptr) -{ - if (script_object_sp) - Reset ((PyObject *)script_object_sp->GetObject()); -} - -void -PythonObject::Dump (Stream &strm) const -{ - if (m_py_obj) - { - FILE *file = ::tmpfile(); - if (file) - { - ::PyObject_Print (m_py_obj, file, 0); - const long length = ftell (file); - if (length) - { - ::rewind(file); - std::vector file_contents (length,'\0'); - const size_t length_read = ::fread (file_contents.data(), 1, file_contents.size(), file); - if (length_read > 0) - strm.Write (file_contents.data(), length_read); - } - ::fclose (file); - } - } - else - strm.PutCString ("NULL"); -} - -PythonString -PythonObject::Repr () -{ - if (!m_py_obj) - return PythonString (); - PyObject *repr = PyObject_Repr(m_py_obj); - if (!repr) - return PythonString (); - return PythonString(repr); -} - -PythonString -PythonObject::Str () -{ - if (!m_py_obj) - return PythonString (); - PyObject *str = PyObject_Str(m_py_obj); - if (!str) - return PythonString (); - return PythonString(str); -} - -bool -PythonObject::IsNULLOrNone () const -{ - return ((m_py_obj == nullptr) || (m_py_obj == Py_None)); -} - -//---------------------------------------------------------------------- -// PythonString -//---------------------------------------------------------------------- - -PythonString::PythonString (PyObject *py_obj) : - PythonObject() -{ - Reset(py_obj); // Use "Reset()" to ensure that py_obj is a string -} - -PythonString::PythonString (const PythonObject &object) : - PythonObject() -{ - Reset(object.get()); // Use "Reset()" to ensure that py_obj is a string -} - -PythonString::PythonString (const lldb::ScriptInterpreterObjectSP &script_object_sp) : - PythonObject() -{ - if (script_object_sp) - Reset((PyObject *)script_object_sp->GetObject()); // Use "Reset()" to ensure that py_obj is a string -} - -PythonString::PythonString (const char* string) : - PythonObject(PyString_FromString(string)) -{ -} - -PythonString::PythonString () : - PythonObject() -{ -} - -PythonString::~PythonString () -{ -} - -bool -PythonString::Reset (PyObject *py_obj) -{ - if (py_obj && PyString_Check(py_obj)) - return PythonObject::Reset(py_obj); - - PythonObject::Reset(nullptr); - return py_obj == nullptr; -} - -const char* -PythonString::GetString() const -{ - if (m_py_obj) - return PyString_AsString(m_py_obj); - return nullptr; -} - -size_t -PythonString::GetSize() const -{ - if (m_py_obj) - return PyString_Size(m_py_obj); - return 0; -} - -void -PythonString::SetString (const char* string) -{ - PythonObject::Reset(PyString_FromString(string)); -} - -//---------------------------------------------------------------------- -// PythonInteger -//---------------------------------------------------------------------- - -PythonInteger::PythonInteger (PyObject *py_obj) : - PythonObject() -{ - Reset(py_obj); // Use "Reset()" to ensure that py_obj is a integer type -} - -PythonInteger::PythonInteger (const PythonObject &object) : - PythonObject() -{ - Reset(object.get()); // Use "Reset()" to ensure that py_obj is a integer type -} - -PythonInteger::PythonInteger (const lldb::ScriptInterpreterObjectSP &script_object_sp) : - PythonObject() -{ - if (script_object_sp) - Reset((PyObject *)script_object_sp->GetObject()); // Use "Reset()" to ensure that py_obj is a string -} - -PythonInteger::PythonInteger (int64_t value) : - PythonObject() -{ - SetInteger (value); -} - - -PythonInteger::~PythonInteger () -{ -} - -bool -PythonInteger::Reset (PyObject *py_obj) -{ - if (py_obj) - { - if (PyInt_Check (py_obj) || PyLong_Check(py_obj)) - return PythonObject::Reset(py_obj); - } - - PythonObject::Reset(nullptr); - return py_obj == nullptr; -} - -int64_t -PythonInteger::GetInteger() -{ - if (m_py_obj) - { - if (PyInt_Check(m_py_obj)) - return PyInt_AsLong(m_py_obj); - else if (PyLong_Check(m_py_obj)) - return PyLong_AsLongLong(m_py_obj); - } - return UINT64_MAX; -} - -void -PythonInteger::SetInteger (int64_t value) -{ - PythonObject::Reset(PyLong_FromLongLong(value)); -} - -//---------------------------------------------------------------------- -// PythonList -//---------------------------------------------------------------------- - -PythonList::PythonList (bool create_empty) : - PythonObject(create_empty ? PyList_New(0) : nullptr) -{ -} - -PythonList::PythonList (uint32_t count) : - PythonObject(PyList_New(count)) -{ -} - -PythonList::PythonList (PyObject *py_obj) : - PythonObject() -{ - Reset(py_obj); // Use "Reset()" to ensure that py_obj is a list -} - - -PythonList::PythonList (const PythonObject &object) : - PythonObject() -{ - Reset(object.get()); // Use "Reset()" to ensure that py_obj is a list -} - -PythonList::PythonList (const lldb::ScriptInterpreterObjectSP &script_object_sp) : - PythonObject() -{ - if (script_object_sp) - Reset((PyObject *)script_object_sp->GetObject()); // Use "Reset()" to ensure that py_obj is a list -} - -PythonList::~PythonList () -{ -} - -bool -PythonList::Reset (PyObject *py_obj) -{ - if (py_obj && PyList_Check(py_obj)) - return PythonObject::Reset(py_obj); - - PythonObject::Reset(nullptr); - return py_obj == nullptr; -} - -uint32_t -PythonList::GetSize() -{ - if (m_py_obj) - return PyList_GET_SIZE(m_py_obj); - return 0; -} - -PythonObject -PythonList::GetItemAtIndex (uint32_t index) -{ - if (m_py_obj) - return PythonObject(PyList_GetItem(m_py_obj, index)); - return PythonObject(); -} - -void -PythonList::SetItemAtIndex (uint32_t index, const PythonObject & object) -{ - if (m_py_obj && object) - 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.get()); -} - -//---------------------------------------------------------------------- -// PythonDictionary -//---------------------------------------------------------------------- - -PythonDictionary::PythonDictionary (bool create_empty) : -PythonObject(create_empty ? PyDict_New() : nullptr) -{ -} - -PythonDictionary::PythonDictionary (PyObject *py_obj) : - PythonObject(py_obj) -{ - Reset(py_obj); // Use "Reset()" to ensure that py_obj is a dictionary -} - - -PythonDictionary::PythonDictionary (const PythonObject &object) : - PythonObject() -{ - Reset(object.get()); // Use "Reset()" to ensure that py_obj is a dictionary -} - -PythonDictionary::PythonDictionary (const lldb::ScriptInterpreterObjectSP &script_object_sp) : - PythonObject () -{ - if (script_object_sp) - Reset((PyObject *)script_object_sp->GetObject()); // Use "Reset()" to ensure that py_obj is a dictionary -} - -PythonDictionary::~PythonDictionary () -{ -} - -bool -PythonDictionary::Reset (PyObject *py_obj) -{ - if (py_obj && PyDict_Check(py_obj)) - return PythonObject::Reset(py_obj); - - PythonObject::Reset(nullptr); - return py_obj == nullptr; -} - -uint32_t -PythonDictionary::GetSize() -{ - if (m_py_obj) - return PyDict_Size(m_py_obj); - return 0; -} - -PythonObject -PythonDictionary::GetItemForKey (const char *key) const -{ - if (key && key[0]) - { - PythonString python_key(key); - return GetItemForKey(python_key); - } - return PythonObject(); -} - - -PythonObject -PythonDictionary::GetItemForKey (const PythonString &key) const -{ - if (m_py_obj && key) - return PythonObject(PyDict_GetItem(m_py_obj, key.get())); - return PythonObject(); -} - - -const char * -PythonDictionary::GetItemForKeyAsString (const PythonString &key, const char *fail_value) const -{ - if (m_py_obj && key) - { - PyObject *py_obj = PyDict_GetItem(m_py_obj, key.get()); - if (py_obj && PyString_Check(py_obj)) - return PyString_AsString(py_obj); - } - return fail_value; -} - -int64_t -PythonDictionary::GetItemForKeyAsInteger (const PythonString &key, int64_t fail_value) const -{ - if (m_py_obj && key) - { - PyObject *py_obj = PyDict_GetItem(m_py_obj, key.get()); - if (py_obj) - { - if (PyInt_Check(py_obj)) - return PyInt_AsLong(py_obj); - - if (PyLong_Check(py_obj)) - return PyLong_AsLong(py_obj); - } - } - return fail_value; -} - -PythonList -PythonDictionary::GetKeys () const -{ - if (m_py_obj) - return PythonList(PyDict_Keys(m_py_obj)); - return PythonList(true); -} - -PythonString -PythonDictionary::GetKeyAtPosition (uint32_t pos) const -{ - PyObject *key, *value; - Py_ssize_t pos_iter = 0; - - if (m_py_obj) - { - while (PyDict_Next(m_py_obj, &pos_iter, &key, &value)) - { - if (pos-- == 0) - return PythonString(key); - } - } - return PythonString(); -} - -PythonObject -PythonDictionary::GetValueAtPosition (uint32_t pos) const -{ - PyObject *key, *value; - Py_ssize_t pos_iter = 0; - - if (!m_py_obj) - return PythonObject(); - - while (PyDict_Next(m_py_obj, &pos_iter, &key, &value)) { - if (pos-- == 0) - return PythonObject(value); - } - return PythonObject(); -} - -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.get(), value.get()); -} - -#endif Index: source/Interpreter/ScriptInterpreter.cpp =================================================================== --- source/Interpreter/ScriptInterpreter.cpp +++ /dev/null @@ -1,166 +0,0 @@ -//===-- ScriptInterpreter.cpp -----------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/lldb-python.h" - -#include "lldb/Interpreter/ScriptInterpreter.h" - -#include -#include -#include - -#include "lldb/Core/Error.h" -#include "lldb/Core/Stream.h" -#include "lldb/Core/StringList.h" -#include "lldb/Interpreter/CommandReturnObject.h" -#include "lldb/Interpreter/ScriptInterpreterPython.h" -#include "lldb/Utility/PseudoTerminal.h" - -using namespace lldb; -using namespace lldb_private; - -ScriptInterpreter::ScriptInterpreter (CommandInterpreter &interpreter, lldb::ScriptLanguage script_lang) : - m_interpreter (interpreter), - m_script_lang (script_lang) -{ -} - -ScriptInterpreter::~ScriptInterpreter () -{ -} - -CommandInterpreter & -ScriptInterpreter::GetCommandInterpreter () -{ - return m_interpreter; -} - -void -ScriptInterpreter::CollectDataForBreakpointCommandCallback -( - std::vector &bp_options_vec, - CommandReturnObject &result -) -{ - result.SetStatus (eReturnStatusFailed); - result.AppendError ("ScriptInterpreter::GetScriptCommands(StringList &) is not implemented."); -} - -void -ScriptInterpreter::CollectDataForWatchpointCommandCallback -( - WatchpointOptions *bp_options, - CommandReturnObject &result -) -{ - result.SetStatus (eReturnStatusFailed); - result.AppendError ("ScriptInterpreter::GetScriptCommands(StringList &) is not implemented."); -} - -std::string -ScriptInterpreter::LanguageToString (lldb::ScriptLanguage language) -{ - std::string return_value; - - switch (language) - { - case eScriptLanguageNone: - return_value = "None"; - break; - case eScriptLanguagePython: - return_value = "Python"; - break; - } - - return return_value; -} - -Error -ScriptInterpreter::SetBreakpointCommandCallback (std::vector &bp_options_vec, - const char *callback_text) -{ - Error return_error; - for (BreakpointOptions *bp_options : bp_options_vec) - { - return_error = SetBreakpointCommandCallback(bp_options, callback_text); - if (return_error.Success()) - break; - } - return return_error; -} - -void -ScriptInterpreter::SetBreakpointCommandCallbackFunction (std::vector &bp_options_vec, - const char *function_name) -{ - for (BreakpointOptions *bp_options : bp_options_vec) - { - SetBreakpointCommandCallbackFunction(bp_options, function_name); - } -} - -std::unique_ptr -ScriptInterpreter::AcquireInterpreterLock () -{ - return std::unique_ptr(new ScriptInterpreterLocker()); -} - -void -ScriptInterpreter::InitializeInterpreter (SWIGInitCallback python_swig_init_callback, - SWIGBreakpointCallbackFunction swig_breakpoint_callback, - SWIGWatchpointCallbackFunction swig_watchpoint_callback, - SWIGPythonTypeScriptCallbackFunction swig_typescript_callback, - SWIGPythonCreateSyntheticProvider swig_synthetic_script, - SWIGPythonCalculateNumChildren swig_calc_children, - SWIGPythonGetChildAtIndex swig_get_child_index, - SWIGPythonGetIndexOfChildWithName swig_get_index_child, - SWIGPythonCastPyObjectToSBValue swig_cast_to_sbvalue , - SWIGPythonGetValueObjectSPFromSBValue swig_get_valobj_sp_from_sbvalue, - SWIGPythonUpdateSynthProviderInstance swig_update_provider, - SWIGPythonMightHaveChildrenSynthProviderInstance swig_mighthavechildren_provider, - SWIGPythonGetValueSynthProviderInstance swig_getvalue_provider, - SWIGPythonCallCommand swig_call_command, - SWIGPythonCallModuleInit swig_call_module_init, - SWIGPythonCreateOSPlugin swig_create_os_plugin, - SWIGPythonScriptKeyword_Process swig_run_script_keyword_process, - SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread, - SWIGPythonScriptKeyword_Target swig_run_script_keyword_target, - SWIGPythonScriptKeyword_Frame swig_run_script_keyword_frame, - SWIGPythonScriptKeyword_Value swig_run_script_keyword_value, - SWIGPython_GetDynamicSetting swig_plugin_get, - SWIGPythonCreateScriptedThreadPlan swig_thread_plan_script, - SWIGPythonCallThreadPlan swig_call_thread_plan) -{ -#ifndef LLDB_DISABLE_PYTHON - ScriptInterpreterPython::InitializeInterpreter (python_swig_init_callback, - swig_breakpoint_callback, - swig_watchpoint_callback, - swig_typescript_callback, - swig_synthetic_script, - swig_calc_children, - swig_get_child_index, - swig_get_index_child, - swig_cast_to_sbvalue , - swig_get_valobj_sp_from_sbvalue, - swig_update_provider, - swig_mighthavechildren_provider, - swig_getvalue_provider, - swig_call_command, - swig_call_module_init, - swig_create_os_plugin, - swig_run_script_keyword_process, - swig_run_script_keyword_thread, - swig_run_script_keyword_target, - swig_run_script_keyword_frame, - swig_run_script_keyword_value, - swig_plugin_get, - swig_thread_plan_script, - swig_call_thread_plan); -#endif // #ifndef LLDB_DISABLE_PYTHON -} Index: source/Interpreter/ScriptInterpreterNone.cpp =================================================================== --- source/Interpreter/ScriptInterpreterNone.cpp +++ /dev/null @@ -1,44 +0,0 @@ -//===-- ScriptInterpreterNone.cpp -------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/lldb-python.h" - -#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" - -using namespace lldb; -using namespace lldb_private; - -ScriptInterpreterNone::ScriptInterpreterNone (CommandInterpreter &interpreter) : - ScriptInterpreter (interpreter, eScriptLanguageNone) -{ -} - -ScriptInterpreterNone::~ScriptInterpreterNone () -{ -} - -bool -ScriptInterpreterNone::ExecuteOneLine (const char *command, CommandReturnObject *, const ExecuteScriptOptions&) -{ - m_interpreter.GetDebugger().GetErrorFile()->PutCString ("error: there is no embedded script interpreter in this mode.\n"); - return false; -} - -void -ScriptInterpreterNone::ExecuteInterpreterLoop () -{ - m_interpreter.GetDebugger().GetErrorFile()->PutCString ("error: there is no embedded script interpreter in this mode.\n"); -} - - Index: source/Interpreter/ScriptInterpreterPython.cpp =================================================================== --- source/Interpreter/ScriptInterpreterPython.cpp +++ /dev/null @@ -1,2887 +0,0 @@ -//===-- ScriptInterpreterPython.cpp -----------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// In order to guarantee correct working with Python, Python.h *MUST* be -// the *FIRST* header file included here. -#ifdef LLDB_DISABLE_PYTHON - -// Python is disabled in this build - -#else - -#include "lldb/lldb-python.h" -#include "lldb/Interpreter/ScriptInterpreterPython.h" - -#include -#include - -#include - -#include "lldb/API/SBValue.h" -#include "lldb/Breakpoint/BreakpointLocation.h" -#include "lldb/Breakpoint/StoppointCallbackContext.h" -#include "lldb/Breakpoint/WatchpointOptions.h" -#include "lldb/Core/Communication.h" -#include "lldb/Core/Debugger.h" -#include "lldb/Core/Timer.h" -#include "lldb/Host/ConnectionFileDescriptor.h" -#include "lldb/Host/HostInfo.h" -#include "lldb/Host/Pipe.h" -#include "lldb/Interpreter/CommandInterpreter.h" -#include "lldb/Interpreter/CommandReturnObject.h" -#include "lldb/Interpreter/PythonDataObjects.h" -#include "lldb/Target/Thread.h" -#include "lldb/Target/ThreadPlan.h" - -#if defined(_WIN32) -#include "lldb/Host/windows/ConnectionGenericFileWindows.h" -#endif - -using namespace lldb; -using namespace lldb_private; - - -static ScriptInterpreter::SWIGInitCallback g_swig_init_callback = nullptr; -static ScriptInterpreter::SWIGBreakpointCallbackFunction g_swig_breakpoint_callback = nullptr; -static ScriptInterpreter::SWIGWatchpointCallbackFunction g_swig_watchpoint_callback = nullptr; -static ScriptInterpreter::SWIGPythonTypeScriptCallbackFunction g_swig_typescript_callback = nullptr; -static ScriptInterpreter::SWIGPythonCreateSyntheticProvider g_swig_synthetic_script = nullptr; -static ScriptInterpreter::SWIGPythonCalculateNumChildren g_swig_calc_children = nullptr; -static ScriptInterpreter::SWIGPythonGetChildAtIndex g_swig_get_child_index = nullptr; -static ScriptInterpreter::SWIGPythonGetIndexOfChildWithName g_swig_get_index_child = nullptr; -static ScriptInterpreter::SWIGPythonCastPyObjectToSBValue g_swig_cast_to_sbvalue = nullptr; -static ScriptInterpreter::SWIGPythonGetValueObjectSPFromSBValue g_swig_get_valobj_sp_from_sbvalue = nullptr; -static ScriptInterpreter::SWIGPythonUpdateSynthProviderInstance g_swig_update_provider = nullptr; -static ScriptInterpreter::SWIGPythonMightHaveChildrenSynthProviderInstance g_swig_mighthavechildren_provider = nullptr; -static ScriptInterpreter::SWIGPythonGetValueSynthProviderInstance g_swig_getvalue_provider = nullptr; -static ScriptInterpreter::SWIGPythonCallCommand g_swig_call_command = nullptr; -static ScriptInterpreter::SWIGPythonCallModuleInit g_swig_call_module_init = nullptr; -static ScriptInterpreter::SWIGPythonCreateOSPlugin g_swig_create_os_plugin = nullptr; -static ScriptInterpreter::SWIGPythonScriptKeyword_Process g_swig_run_script_keyword_process = nullptr; -static ScriptInterpreter::SWIGPythonScriptKeyword_Thread g_swig_run_script_keyword_thread = nullptr; -static ScriptInterpreter::SWIGPythonScriptKeyword_Target g_swig_run_script_keyword_target = nullptr; -static ScriptInterpreter::SWIGPythonScriptKeyword_Frame g_swig_run_script_keyword_frame = nullptr; -static ScriptInterpreter::SWIGPythonScriptKeyword_Value g_swig_run_script_keyword_value = nullptr; -static ScriptInterpreter::SWIGPython_GetDynamicSetting g_swig_plugin_get = nullptr; -static ScriptInterpreter::SWIGPythonCreateScriptedThreadPlan g_swig_thread_plan_script = nullptr; -static ScriptInterpreter::SWIGPythonCallThreadPlan g_swig_call_thread_plan = nullptr; - -static std::string -ReadPythonBacktrace (PyObject* py_backtrace); - -ScriptInterpreterPython::Locker::Locker (ScriptInterpreterPython *py_interpreter, - uint16_t on_entry, - uint16_t on_leave, - FILE *in, - FILE *out, - FILE *err) : - ScriptInterpreterLocker (), - m_teardown_session( (on_leave & TearDownSession) == TearDownSession ), - m_python_interpreter(py_interpreter) -{ - DoAcquireLock(); - if ((on_entry & InitSession) == InitSession) - { - if (DoInitSession(on_entry, in, out, err) == false) - { - // Don't teardown the session if we didn't init it. - m_teardown_session = false; - } - } -} - -bool -ScriptInterpreterPython::Locker::DoAcquireLock() -{ - Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT | LIBLLDB_LOG_VERBOSE)); - m_GILState = PyGILState_Ensure(); - if (log) - log->Printf("Ensured PyGILState. Previous state = %slocked\n", m_GILState == PyGILState_UNLOCKED ? "un" : ""); - - // we need to save the thread state when we first start the command - // because we might decide to interrupt it while some action is taking - // place outside of Python (e.g. printing to screen, waiting for the network, ...) - // in that case, _PyThreadState_Current will be NULL - and we would be unable - // to set the asynchronous exception - not a desirable situation - m_python_interpreter->SetThreadState (_PyThreadState_Current); - m_python_interpreter->IncrementLockCount(); - return true; -} - -bool -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 (on_entry_flags, in, out, err); -} - -bool -ScriptInterpreterPython::Locker::DoFreeLock() -{ - Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT | LIBLLDB_LOG_VERBOSE)); - if (log) - log->Printf("Releasing PyGILState. Returning to state = %slocked\n", m_GILState == PyGILState_UNLOCKED ? "un" : ""); - PyGILState_Release(m_GILState); - m_python_interpreter->DecrementLockCount(); - return true; -} - -bool -ScriptInterpreterPython::Locker::DoTearDownSession() -{ - if (!m_python_interpreter) - return false; - m_python_interpreter->LeaveSession (); - return true; -} - -ScriptInterpreterPython::Locker::~Locker() -{ - if (m_teardown_session) - DoTearDownSession(); - DoFreeLock(); -} - - -ScriptInterpreterPython::ScriptInterpreterPython (CommandInterpreter &interpreter) : - ScriptInterpreter (interpreter, eScriptLanguagePython), - 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_lock_count (0), - m_command_thread_state (nullptr) -{ - - ScriptInterpreterPython::InitializePrivate (); - - m_dictionary_name.append("_dict"); - StreamString run_string; - run_string.Printf ("%s = dict()", m_dictionary_name.c_str()); - - Locker locker(this, - ScriptInterpreterPython::Locker::AcquireLock, - ScriptInterpreterPython::Locker::FreeAcquiredLock); - PyRun_SimpleString (run_string.GetData()); - - run_string.Clear(); - - // Importing 'lldb' module calls SBDebugger::Initialize, which calls Debugger::Initialize, which increments a - // global debugger ref-count; therefore we need to check the ref-count before and after importing lldb, and if the - // ref-count increased we need to call Debugger::Terminate here to decrement the ref-count so that when the final - // call to Debugger::Terminate is made, the ref-count has the correct value. - // - // Bonus question: Why doesn't the ref-count always increase? Because sometimes lldb has already been imported, in - // which case the code inside it, including the call to SBDebugger::Initialize(), does not get executed. - - int old_count = Debugger::TestDebuggerRefCount(); - - run_string.Printf ("run_one_line (%s, 'import copy, keyword, os, re, sys, uuid, lldb')", m_dictionary_name.c_str()); - PyRun_SimpleString (run_string.GetData()); - - // WARNING: temporary code that loads Cocoa formatters - this should be done on a per-platform basis rather than loading the whole set - // and letting the individual formatter classes exploit APIs to check whether they can/cannot do their task - 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()); -} - -ScriptInterpreterPython::~ScriptInterpreterPython () -{ -} - -void -ScriptInterpreterPython::IOHandlerActivated (IOHandler &io_handler) -{ - const char *instructions = nullptr; - - switch (m_active_io_handler) - { - 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 (instructions) - { - StreamFileSP output_sp(io_handler.GetOutputStreamFile()); - if (output_sp) - { - output_sp->PutCString(instructions); - output_sp->Flush(); - } - } -} - -void -ScriptInterpreterPython::IOHandlerInputComplete (IOHandler &io_handler, std::string &data) -{ - io_handler.SetIsDone(true); - bool batch_mode = m_interpreter.GetBatchCommandMode(); - - switch (m_active_io_handler) - { - case eIOHandlerNone: - break; - case eIOHandlerBreakpoint: - { - std::vector *bp_options_vec = (std::vector *)io_handler.GetUserData(); - for (auto bp_options : *bp_options_vec) - { - if (!bp_options) - continue; - - std::unique_ptr 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).Success()) - { - 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 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; - } -} - - -void -ScriptInterpreterPython::ResetOutputFileHandle (FILE *fh) -{ -} - -void -ScriptInterpreterPython::SaveTerminalState (int fd) -{ - // Python mucks with the terminal state of STDIN. If we can possibly avoid - // this by setting the file handles up correctly prior to entering the - // interpreter we should. For now we save and restore the terminal state - // on the input file handle. - m_terminal_state.Save (fd, false); -} - -void -ScriptInterpreterPython::RestoreTerminalState () -{ - // Python mucks with the terminal state of STDIN. If we can possibly avoid - // this by setting the file handles up correctly prior to entering the - // interpreter we should. For now we save and restore the terminal state - // on the input file handle. - m_terminal_state.Restore(); -} - -void -ScriptInterpreterPython::LeaveSession () -{ - Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT)); - if (log) - log->PutCString("ScriptInterpreterPython::LeaveSession()"); - - // checking that we have a valid thread state - since we use our own threading and locking - // in some (rare) cases during cleanup Python may end up believing we have no thread state - // and PyImport_AddModule will crash if that is the case - since that seems to only happen - // when destroying the SBDebugger, we can make do without clearing up stdout and stderr - - // rdar://problem/11292882 - // When the current thread state is NULL, PyThreadState_Get() issues a fatal error. - if (PyThreadState_GetDict()) - { - PythonDictionary &sys_module_dict = GetSysModuleDictionary (); - if (sys_module_dict) - { - 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 (); - } - } - } - - m_session_is_active = false; -} - -bool -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. - Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT)); - if (m_session_is_active) - { - if (log) - 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(on_entry_flags=0x%" PRIx16 ")", on_entry_flags); - - - m_session_is_active = true; - - StreamString run_string; - - 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()); - run_string.PutCString ("; lldb.target = lldb.debugger.GetSelectedTarget()"); - run_string.PutCString ("; lldb.process = lldb.target.GetProcess()"); - run_string.PutCString ("; lldb.thread = lldb.process.GetSelectedThread ()"); - run_string.PutCString ("; lldb.frame = lldb.thread.GetSelectedFrame ()"); - run_string.PutCString ("')"); - } - 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 ( "; lldb.debugger = lldb.SBDebugger.FindDebuggerWithID (%" PRIu64 ")", GetCommandInterpreter().GetDebugger().GetID()); - run_string.PutCString ("')"); - } - - PyRun_SimpleString (run_string.GetData()); - run_string.Clear(); - - PythonDictionary &sys_module_dict = GetSysModuleDictionary (); - if (sys_module_dict) - { - lldb::StreamFileSP in_sp; - lldb::StreamFileSP out_sp; - lldb::StreamFileSP err_sp; - if (in == nullptr || out == nullptr || err == nullptr) - m_interpreter.GetDebugger().AdoptTopIOHandlerFilesIfInvalid (in_sp, out_sp, err_sp); - - m_saved_stdin.Reset(); - - if ((on_entry_flags & Locker::NoSTDIN) == 0) - { - // STDIN is enabled - if (in == nullptr && in_sp) - in = in_sp->GetFile().GetStream(); - if (in) - { - m_saved_stdin.Reset(sys_module_dict.GetItemForKey("stdin")); - // This call can deadlock your process if the file is locked - PyObject *new_file = PyFile_FromFile (in, (char *) "", (char *) "r", nullptr); - sys_module_dict.SetItemForKey ("stdin", new_file); - Py_DECREF (new_file); - } - } - - if (out == nullptr && 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", nullptr); - sys_module_dict.SetItemForKey ("stdout", new_file); - Py_DECREF (new_file); - } - else - m_saved_stdout.Reset(); - - if (err == nullptr && 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", nullptr); - sys_module_dict.SetItemForKey ("stderr", new_file); - Py_DECREF (new_file); - } - else - m_saved_stderr.Reset(); - } - - if (PyErr_Occurred()) - PyErr_Clear (); - - return true; -} - -PythonObject & -ScriptInterpreterPython::GetMainModule () -{ - if (!m_main_module) - m_main_module.Reset(PyImport_AddModule ("__main__")); - return m_main_module; -} - -PythonDictionary & -ScriptInterpreterPython::GetSessionDictionary () -{ - if (!m_session_dict) - { - PythonObject &main_module = GetMainModule (); - if (main_module) - { - PythonDictionary main_dict(PyModule_GetDict (main_module.get())); - if (main_dict) - { - m_session_dict = main_dict.GetItemForKey(m_dictionary_name.c_str()); - } - } - } - 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 -GenerateUniqueName (const char* base_name_wanted, - uint32_t& functions_counter, - const void* name_token = nullptr) -{ - StreamString sstr; - - if (!base_name_wanted) - return std::string(); - - if (!name_token) - sstr.Printf ("%s_%d", base_name_wanted, functions_counter++); - else - sstr.Printf ("%s_%p", base_name_wanted, name_token); - - return sstr.GetString(); -} - -bool -ScriptInterpreterPython::GetEmbeddedInterpreterModuleObjects () -{ - if (!m_run_one_line_function) - { - PyObject *module = PyImport_AddModule ("lldb.embedded_interpreter"); - if (module != nullptr) - { - PythonDictionary module_dict (PyModule_GetDict (module)); - if (module_dict) - { - m_run_one_line_function = module_dict.GetItemForKey("run_one_line"); - m_run_one_line_str_global = module_dict.GetItemForKey("g_run_one_line_str"); - } - } - } - return (bool)m_run_one_line_function; -} - -static void -ReadThreadBytesReceived(void *baton, const void *src, size_t src_len) -{ - if (src && src_len) - { - Stream *strm = (Stream *)baton; - strm->Write(src, src_len); - strm->Flush(); - } -} - -bool -ScriptInterpreterPython::ExecuteOneLine (const char *command, CommandReturnObject *result, const ExecuteScriptOptions &options) -{ - if (!m_valid_session) - return false; - - if (command && command[0]) - { - // We want to call run_one_line, passing in the dictionary and the command string. We cannot do this through - // PyRun_SimpleString here because the command string may contain escaped characters, and putting it inside - // another string to pass to PyRun_SimpleString messes up the escaping. So we use the following more complicated - // method to pass the command string directly down to Python. - Debugger &debugger = m_interpreter.GetDebugger(); - - StreamFileSP input_file_sp; - StreamFileSP output_file_sp; - StreamFileSP error_file_sp; - Communication output_comm ("lldb.ScriptInterpreterPython.ExecuteOneLine.comm"); - bool join_read_thread = false; - if (options.GetEnableIO()) - { - if (result) - { - input_file_sp = debugger.GetInputFile(); - // Set output to a temporary file so we can forward the results on to the result object - - Pipe pipe; - Error pipe_result = pipe.CreateNew(false); - if (pipe_result.Success()) - { -#if defined(_WIN32) - lldb::file_t read_file = pipe.GetReadNativeHandle(); - pipe.ReleaseReadFileDescriptor(); - std::unique_ptr conn_ap(new ConnectionGenericFile(read_file, true)); -#else - std::unique_ptr conn_ap(new ConnectionFileDescriptor(pipe.ReleaseReadFileDescriptor(), true)); -#endif - if (conn_ap->IsConnected()) - { - output_comm.SetConnection(conn_ap.release()); - output_comm.SetReadThreadBytesReceivedCallback(ReadThreadBytesReceived, &result->GetOutputStream()); - output_comm.StartReadThread(); - join_read_thread = true; - FILE *outfile_handle = fdopen (pipe.ReleaseWriteFileDescriptor(), "w"); - output_file_sp.reset(new StreamFile(outfile_handle, true)); - error_file_sp = output_file_sp; - if (outfile_handle) - ::setbuf (outfile_handle, nullptr); - - result->SetImmediateOutputFile(debugger.GetOutputFile()->GetFile().GetStream()); - result->SetImmediateErrorFile(debugger.GetErrorFile()->GetFile().GetStream()); - } - } - } - if (!input_file_sp || !output_file_sp || !error_file_sp) - debugger.AdoptTopIOHandlerFilesIfInvalid(input_file_sp, output_file_sp, error_file_sp); - } - else - { - input_file_sp.reset (new StreamFile ()); - input_file_sp->GetFile().Open("/dev/null", File::eOpenOptionRead); - output_file_sp.reset (new StreamFile ()); - output_file_sp->GetFile().Open("/dev/null", File::eOpenOptionWrite); - error_file_sp = output_file_sp; - } - - 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) | - ((result && result->GetInteractive()) ? 0: Locker::NoSTDIN), - 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) - { - PythonObject return_value(PyObject_CallObject (pfunc, pargs.get())); - if (return_value) - success = true; - else if (options.GetMaskoutErrors() && PyErr_Occurred ()) - { - PyErr_Print(); - PyErr_Clear(); - } - } - } - } - } - - // Flush our output and error file handles - ::fflush (out_file); - if (out_file != err_file) - ::fflush (err_file); - - if (join_read_thread) - { - // 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; - - // The one-liner failed. Append the error message. - if (result) - result->AppendErrorWithFormat ("python failed attempting to evaluate '%s'\n", command); - return false; - } - - if (result) - result->AppendError ("empty command passed to python\n"); - return false; -} - - -class IOHandlerPythonInterpreter : - public IOHandler -{ -public: - - IOHandlerPythonInterpreter (Debugger &debugger, - ScriptInterpreterPython *python) : - IOHandler (debugger, IOHandler::Type::PythonInterpreter), - m_python(python) - { - - } - - virtual - ~IOHandlerPythonInterpreter() - { - - } - - virtual ConstString - GetControlSequence (char ch) - { - if (ch == 'd') - return ConstString("quit()\n"); - return ConstString(); - } - - virtual void - Run () - { - if (m_python) - { - int stdin_fd = GetInputFD(); - if (stdin_fd >= 0) - { - Terminal terminal(stdin_fd); - TerminalState terminal_state; - const bool is_a_tty = terminal.IsATerminal(); - - if (is_a_tty) - { - terminal_state.Save (stdin_fd, false); - terminal.SetCanonical(false); - terminal.SetEcho(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(); - } - } - SetIsDone(true); - } - - virtual void - Hide () - { - - } - - virtual void - Refresh () - { - - } - - virtual void - Cancel () - { - - } - - virtual bool - Interrupt () - { - return m_python->Interrupt(); - } - - virtual void - GotEOF() - { - - } -protected: - ScriptInterpreterPython *m_python; -}; - - -void -ScriptInterpreterPython::ExecuteInterpreterLoop () -{ - Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__); - - Debugger &debugger = GetCommandInterpreter().GetDebugger(); - - // At the moment, the only time the debugger does not have an input file handle is when this is called - // directly from Python, in which case it is both dangerous and unnecessary (not to mention confusing) to - // try to embed a running interpreter loop inside the already running Python interpreter loop, so we won't - // do it. - - if (!debugger.GetInputFile()->GetFile().IsValid()) - return; - - IOHandlerSP io_handler_sp (new IOHandlerPythonInterpreter (debugger, this)); - if (io_handler_sp) - { - debugger.PushIOHandler(io_handler_sp); - } -} - -bool -ScriptInterpreterPython::Interrupt() -{ - Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT)); - - if (IsExecutingPython()) - { - PyThreadState* state = _PyThreadState_Current; - if (!state) - state = GetThreadState(); - if (state) - { - long tid = state->thread_id; - _PyThreadState_Current = state; - int num_threads = PyThreadState_SetAsyncExc(tid, PyExc_KeyboardInterrupt); - if (log) - log->Printf("ScriptInterpreterPython::Interrupt() sending PyExc_KeyboardInterrupt (tid = %li, num_threads = %i)...", tid, num_threads); - return true; - } - } - if (log) - log->Printf("ScriptInterpreterPython::Interrupt() python code not running, can't interrupt"); - return false; - -} -bool -ScriptInterpreterPython::ExecuteOneLineWithReturn (const char *in_string, - ScriptInterpreter::ScriptReturnType return_type, - void *ret_value, - const ExecuteScriptOptions &options) -{ - - Locker locker(this, - ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0) | Locker::NoSTDIN, - ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession); - - PyObject *py_return = nullptr; - PythonObject &main_module = GetMainModule (); - PythonDictionary globals (PyModule_GetDict(main_module.get())); - PyObject *py_error = nullptr; - bool ret_success = false; - int success; - - PythonDictionary locals = GetSessionDictionary (); - - if (!locals) - { - locals = PyObject_GetAttrString (globals.get(), m_dictionary_name.c_str()); - } - - if (!locals) - locals = globals; - - py_error = PyErr_Occurred(); - if (py_error != nullptr) - PyErr_Clear(); - - if (in_string != nullptr) - { - { // scope for PythonInputReaderManager - //PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL); - py_return = PyRun_String (in_string, Py_eval_input, globals.get(), locals.get()); - if (py_return == nullptr) - { - py_error = PyErr_Occurred (); - if (py_error != nullptr) - PyErr_Clear (); - - py_return = PyRun_String (in_string, Py_single_input, globals.get(), locals.get()); - } - } - - if (py_return != nullptr) - { - switch (return_type) - { - case eScriptReturnTypeCharPtr: // "char *" - { - const char format[3] = "s#"; - success = PyArg_Parse (py_return, format, (char **) ret_value); - break; - } - case eScriptReturnTypeCharStrOrNone: // char* or NULL if py_return == Py_None - { - const char format[3] = "z"; - success = PyArg_Parse (py_return, format, (char **) ret_value); - break; - } - case eScriptReturnTypeBool: - { - const char format[2] = "b"; - success = PyArg_Parse (py_return, format, (bool *) ret_value); - break; - } - case eScriptReturnTypeShortInt: - { - const char format[2] = "h"; - success = PyArg_Parse (py_return, format, (short *) ret_value); - break; - } - case eScriptReturnTypeShortIntUnsigned: - { - const char format[2] = "H"; - success = PyArg_Parse (py_return, format, (unsigned short *) ret_value); - break; - } - case eScriptReturnTypeInt: - { - const char format[2] = "i"; - success = PyArg_Parse (py_return, format, (int *) ret_value); - break; - } - case eScriptReturnTypeIntUnsigned: - { - const char format[2] = "I"; - success = PyArg_Parse (py_return, format, (unsigned int *) ret_value); - break; - } - case eScriptReturnTypeLongInt: - { - const char format[2] = "l"; - success = PyArg_Parse (py_return, format, (long *) ret_value); - break; - } - case eScriptReturnTypeLongIntUnsigned: - { - const char format[2] = "k"; - success = PyArg_Parse (py_return, format, (unsigned long *) ret_value); - break; - } - case eScriptReturnTypeLongLong: - { - const char format[2] = "L"; - success = PyArg_Parse (py_return, format, (long long *) ret_value); - break; - } - case eScriptReturnTypeLongLongUnsigned: - { - const char format[2] = "K"; - success = PyArg_Parse (py_return, format, (unsigned long long *) ret_value); - break; - } - case eScriptReturnTypeFloat: - { - const char format[2] = "f"; - success = PyArg_Parse (py_return, format, (float *) ret_value); - break; - } - case eScriptReturnTypeDouble: - { - const char format[2] = "d"; - success = PyArg_Parse (py_return, format, (double *) ret_value); - break; - } - case eScriptReturnTypeChar: - { - const char format[2] = "c"; - success = PyArg_Parse (py_return, format, (char *) ret_value); - break; - } - case eScriptReturnTypeOpaqueObject: - { - success = true; - Py_XINCREF(py_return); - *((PyObject**)ret_value) = py_return; - break; - } - } - Py_XDECREF (py_return); - if (success) - ret_success = true; - else - ret_success = false; - } - } - - py_error = PyErr_Occurred(); - if (py_error != nullptr) - { - ret_success = false; - if (options.GetMaskoutErrors()) - { - if (PyErr_GivenExceptionMatches (py_error, PyExc_SyntaxError)) - PyErr_Print (); - PyErr_Clear(); - } - } - - return ret_success; -} - -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) | Locker::NoSTDIN, - ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession); - - PythonObject return_value; - PythonObject &main_module = GetMainModule (); - PythonDictionary globals (PyModule_GetDict(main_module.get())); - PyObject *py_error = nullptr; - - PythonDictionary locals = GetSessionDictionary (); - - if (!locals) - { - locals = PyObject_GetAttrString (globals.get(), m_dictionary_name.c_str()); - } - - if (!locals) - { - locals = globals; - } - - py_error = PyErr_Occurred(); - if (py_error != nullptr) - PyErr_Clear(); - - if (in_string != nullptr) - { - struct _node *compiled_node = PyParser_SimpleParseString (in_string, Py_file_input); - if (compiled_node) - { - PyCodeObject *compiled_code = PyNode_Compile (compiled_node, "temp.py"); - if (compiled_code) - { - return_value.Reset(PyEval_EvalCode (compiled_code, globals.get(), locals.get())); - } - } - } - - py_error = PyErr_Occurred (); - if (py_error != nullptr) - { -// puts(in_string); -// _PyObject_Dump (py_error); -// PyErr_Print(); -// success = false; - - PyObject *type = nullptr; - PyObject *value = nullptr; - PyObject *traceback = nullptr; - PyErr_Fetch (&type,&value,&traceback); - - // get the backtrace - std::string bt = ReadPythonBacktrace(traceback); - - 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()) - { - PyErr_Clear(); - } - } - - return error; -} - - -void -ScriptInterpreterPython::CollectDataForBreakpointCommandCallback (std::vector &bp_options_vec, - CommandReturnObject &result) -{ - m_active_io_handler = eIOHandlerBreakpoint; - m_interpreter.GetPythonCommandsFromIOHandler (" ", *this, true, &bp_options_vec); -} - -void -ScriptInterpreterPython::CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options, - CommandReturnObject &result) -{ - m_active_io_handler = eIOHandlerWatchpoint; - m_interpreter.GetPythonCommandsFromIOHandler (" ", *this, true, wp_options); -} - -void -ScriptInterpreterPython::SetBreakpointCommandCallbackFunction (BreakpointOptions *bp_options, - const char *function_name) -{ - // For now just cons up a oneliner that calls the provided function. - std::string oneliner("return "); - oneliner += function_name; - oneliner += "(frame, bp_loc, internal_dict)"; - m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options, - oneliner.c_str()); -} - -// Set a Python one-liner as the callback for the breakpoint. -Error -ScriptInterpreterPython::SetBreakpointCommandCallback (BreakpointOptions *bp_options, - const char *command_body_text) -{ - std::unique_ptr data_ap(new BreakpointOptions::CommandData()); - - // Split the command_body_text into lines, and pass that to GenerateBreakpointCommandCallbackData. That will - // wrap the body in an auto-generated function, and return the function name in script_source. That is what - // the callback will actually invoke. - - data_ap->user_source.SplitIntoLines(command_body_text); - Error error = GenerateBreakpointCommandCallbackData (data_ap->user_source, data_ap->script_source); - if (error.Success()) - { - BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); - bp_options->SetCallback (ScriptInterpreterPython::BreakpointCallbackFunction, baton_sp); - return error; - } - else - return error; -} - -// Set a Python one-liner as the callback for the watchpoint. -void -ScriptInterpreterPython::SetWatchpointCommandCallback (WatchpointOptions *wp_options, - const char *oneliner) -{ - std::unique_ptr data_ap(new WatchpointOptions::CommandData()); - - // It's necessary to set both user_source and script_source to the oneliner. - // The former is used to generate callback description (as in watchpoint command list) - // while the latter is used for Python to interpret during the actual callback. - - data_ap->user_source.AppendString (oneliner); - data_ap->script_source.assign (oneliner); - - 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); - } - - return; -} - -Error -ScriptInterpreterPython::ExportFunctionDefinitionToInterpreter (StringList &function_def) -{ - // Convert StringList to one long, newline delimited, const char *. - std::string function_def_string(function_def.CopyList()); - - Error error = ExecuteMultipleLines (function_def_string.c_str(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false)); - return error; -} - -Error -ScriptInterpreterPython::GenerateFunction(const char *signature, const StringList &input) -{ - Error error; - int num_lines = input.GetSize (); - if (num_lines == 0) - { - error.SetErrorString ("No input data."); - return error; - } - - if (!signature || *signature == 0) - { - error.SetErrorString("No output function name."); - return error; - } - - StreamString sstr; - StringList auto_generated_function; - auto_generated_function.AppendString (signature); - auto_generated_function.AppendString (" global_dict = globals()"); // Grab the global dictionary - auto_generated_function.AppendString (" new_keys = internal_dict.keys()"); // Make a list of keys in the session dict - auto_generated_function.AppendString (" old_keys = global_dict.keys()"); // Save list of keys in global dict - auto_generated_function.AppendString (" global_dict.update (internal_dict)"); // Add the session dictionary to the - // global dictionary. - - // Wrap everything up inside the function, increasing the indentation. - - auto_generated_function.AppendString(" if True:"); - for (int i = 0; i < num_lines; ++i) - { - sstr.Clear (); - sstr.Printf (" %s", input.GetStringAtIndex (i)); - auto_generated_function.AppendString (sstr.GetData()); - } - auto_generated_function.AppendString (" for key in new_keys:"); // Iterate over all the keys from session dict - auto_generated_function.AppendString (" internal_dict[key] = global_dict[key]"); // Update session dict values - auto_generated_function.AppendString (" if key not in old_keys:"); // If key was not originally in global dict - auto_generated_function.AppendString (" del global_dict[key]"); // ...then remove key/value from global dict - - // Verify that the results are valid Python. - - error = ExportFunctionDefinitionToInterpreter (auto_generated_function); - - return error; -} - -bool -ScriptInterpreterPython::GenerateTypeScriptFunction (StringList &user_input, std::string& output, const void* name_token) -{ - static uint32_t num_created_functions = 0; - user_input.RemoveBlankLines (); - StreamString sstr; - - // Check to see if we have any data; if not, just return. - if (user_input.GetSize() == 0) - return false; - - // Take what the user wrote, wrap it all up inside one big auto-generated Python function, passing in the - // ValueObject as parameter to the function. - - std::string auto_generated_function_name(GenerateUniqueName("lldb_autogen_python_type_print_func", num_created_functions, name_token)); - sstr.Printf ("def %s (valobj, internal_dict):", auto_generated_function_name.c_str()); - - if (!GenerateFunction(sstr.GetData(), user_input).Success()) - return false; - - // Store the name of the auto-generated function to be called. - output.assign(auto_generated_function_name); - return true; -} - -bool -ScriptInterpreterPython::GenerateScriptAliasFunction (StringList &user_input, std::string &output) -{ - static uint32_t num_created_functions = 0; - user_input.RemoveBlankLines (); - StreamString sstr; - - // Check to see if we have any data; if not, just return. - if (user_input.GetSize() == 0) - return false; - - std::string auto_generated_function_name(GenerateUniqueName("lldb_autogen_python_cmd_alias_func", num_created_functions)); - - sstr.Printf ("def %s (debugger, args, result, internal_dict):", auto_generated_function_name.c_str()); - - if (!GenerateFunction(sstr.GetData(),user_input).Success()) - return false; - - // Store the name of the auto-generated function to be called. - output.assign(auto_generated_function_name); - return true; -} - - -bool -ScriptInterpreterPython::GenerateTypeSynthClass (StringList &user_input, std::string &output, const void* name_token) -{ - static uint32_t num_created_classes = 0; - user_input.RemoveBlankLines (); - int num_lines = user_input.GetSize (); - StreamString sstr; - - // Check to see if we have any data; if not, just return. - if (user_input.GetSize() == 0) - return false; - - // Wrap all user input into a Python class - - std::string auto_generated_class_name(GenerateUniqueName("lldb_autogen_python_type_synth_class",num_created_classes,name_token)); - - StringList auto_generated_class; - - // Create the function name & definition string. - - sstr.Printf ("class %s:", auto_generated_class_name.c_str()); - auto_generated_class.AppendString (sstr.GetData()); - - // Wrap everything up inside the class, increasing the indentation. - // we don't need to play any fancy indentation tricks here because there is no - // surrounding code whose indentation we need to honor - for (int i = 0; i < num_lines; ++i) - { - sstr.Clear (); - sstr.Printf (" %s", user_input.GetStringAtIndex (i)); - auto_generated_class.AppendString (sstr.GetData()); - } - - - // Verify that the results are valid Python. - // (even though the method is ExportFunctionDefinitionToInterpreter, a class will actually be exported) - // (TODO: rename that method to ExportDefinitionToInterpreter) - if (!ExportFunctionDefinitionToInterpreter (auto_generated_class).Success()) - return false; - - // Store the name of the auto-generated class - - output.assign(auto_generated_class_name); - return true; -} - -lldb::ScriptInterpreterObjectSP -ScriptInterpreterPython::OSPlugin_CreatePluginObject (const char *class_name, lldb::ProcessSP process_sp) -{ - if (class_name == nullptr || class_name[0] == '\0') - return lldb::ScriptInterpreterObjectSP(); - - if (!process_sp) - return lldb::ScriptInterpreterObjectSP(); - - void* ret_val; - - { - 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); - } - - return MakeScriptObject(ret_val); -} - -lldb::ScriptInterpreterObjectSP -ScriptInterpreterPython::OSPlugin_RegisterInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp) -{ - Locker py_lock(this, - Locker::AcquireLock | Locker::NoSTDIN, - Locker::FreeLock); - - static char callee_name[] = "get_register_info"; - - if (!os_plugin_object_sp) - return lldb::ScriptInterpreterObjectSP(); - - PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject(); - - if (implementor == nullptr || implementor == Py_None) - return lldb::ScriptInterpreterObjectSP(); - - PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); - - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - if (pmeth == nullptr || pmeth == Py_None) - { - Py_XDECREF(pmeth); - return lldb::ScriptInterpreterObjectSP(); - } - - if (PyCallable_Check(pmeth) == 0) - { - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - Py_XDECREF(pmeth); - return lldb::ScriptInterpreterObjectSP(); - } - - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - Py_XDECREF(pmeth); - - // right now we know this function exists and is callable.. - PyObject* py_return = PyObject_CallMethod(implementor, callee_name, nullptr); - - // if it fails, print the error but otherwise go on - if (PyErr_Occurred()) - { - PyErr_Print(); - PyErr_Clear(); - } - - return MakeScriptObject(py_return); -} - -lldb::ScriptInterpreterObjectSP -ScriptInterpreterPython::OSPlugin_ThreadsInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp) -{ - Locker py_lock (this, - Locker::AcquireLock | Locker::NoSTDIN, - Locker::FreeLock); - - static char callee_name[] = "get_thread_info"; - - if (!os_plugin_object_sp) - return lldb::ScriptInterpreterObjectSP(); - - PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject(); - - if (implementor == nullptr || implementor == Py_None) - return lldb::ScriptInterpreterObjectSP(); - - PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); - - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - if (pmeth == nullptr || pmeth == Py_None) - { - Py_XDECREF(pmeth); - return lldb::ScriptInterpreterObjectSP(); - } - - if (PyCallable_Check(pmeth) == 0) - { - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - Py_XDECREF(pmeth); - return lldb::ScriptInterpreterObjectSP(); - } - - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - Py_XDECREF(pmeth); - - // right now we know this function exists and is callable.. - PyObject* py_return = PyObject_CallMethod(implementor, callee_name, nullptr); - - // if it fails, print the error but otherwise go on - if (PyErr_Occurred()) - { - PyErr_Print(); - PyErr_Clear(); - } - - return MakeScriptObject(py_return); -} - -// GetPythonValueFormatString provides a system independent type safe way to -// convert a variable's type into a python value format. Python value formats -// are defined in terms of builtin C types and could change from system to -// as the underlying typedef for uint* types, size_t, off_t and other values -// change. - -template -const char *GetPythonValueFormatString(T t) -{ - assert(!"Unhandled type passed to GetPythonValueFormatString(T), make a specialization of GetPythonValueFormatString() to support this type."); - return nullptr; -} -template <> const char *GetPythonValueFormatString (char *) { return "s"; } -template <> const char *GetPythonValueFormatString (char) { return "b"; } -template <> const char *GetPythonValueFormatString (unsigned char) { return "B"; } -template <> const char *GetPythonValueFormatString (short) { return "h"; } -template <> const char *GetPythonValueFormatString (unsigned short) { return "H"; } -template <> const char *GetPythonValueFormatString (int) { return "i"; } -template <> const char *GetPythonValueFormatString (unsigned int) { return "I"; } -template <> const char *GetPythonValueFormatString (long) { return "l"; } -template <> const char *GetPythonValueFormatString (unsigned long) { return "k"; } -template <> const char *GetPythonValueFormatString (long long) { return "L"; } -template <> const char *GetPythonValueFormatString (unsigned long long) { return "K"; } -template <> const char *GetPythonValueFormatString (float t) { return "f"; } -template <> const char *GetPythonValueFormatString (double t) { return "d"; } - -lldb::ScriptInterpreterObjectSP -ScriptInterpreterPython::OSPlugin_RegisterContextData (lldb::ScriptInterpreterObjectSP os_plugin_object_sp, - lldb::tid_t tid) -{ - Locker py_lock (this, - Locker::AcquireLock | Locker::NoSTDIN, - Locker::FreeLock); - - static char callee_name[] = "get_register_data"; - static char *param_format = const_cast(GetPythonValueFormatString(tid)); - - if (!os_plugin_object_sp) - return lldb::ScriptInterpreterObjectSP(); - - PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject(); - - if (implementor == nullptr || implementor == Py_None) - return lldb::ScriptInterpreterObjectSP(); - - PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); - - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - if (pmeth == nullptr || pmeth == Py_None) - { - Py_XDECREF(pmeth); - return lldb::ScriptInterpreterObjectSP(); - } - - if (PyCallable_Check(pmeth) == 0) - { - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - Py_XDECREF(pmeth); - return lldb::ScriptInterpreterObjectSP(); - } - - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - Py_XDECREF(pmeth); - - // right now we know this function exists and is callable.. - PyObject* py_return = PyObject_CallMethod(implementor, callee_name, param_format, tid); - - // if it fails, print the error but otherwise go on - if (PyErr_Occurred()) - { - PyErr_Print(); - PyErr_Clear(); - } - - return MakeScriptObject(py_return); -} - -lldb::ScriptInterpreterObjectSP -ScriptInterpreterPython::OSPlugin_CreateThread (lldb::ScriptInterpreterObjectSP os_plugin_object_sp, - lldb::tid_t tid, - lldb::addr_t context) -{ - Locker py_lock(this, - Locker::AcquireLock | Locker::NoSTDIN, - Locker::FreeLock); - - static char callee_name[] = "create_thread"; - std::string param_format; - param_format += GetPythonValueFormatString(tid); - param_format += GetPythonValueFormatString(context); - - if (!os_plugin_object_sp) - return lldb::ScriptInterpreterObjectSP(); - - PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject(); - - if (implementor == nullptr || implementor == Py_None) - return lldb::ScriptInterpreterObjectSP(); - - PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); - - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - if (pmeth == nullptr || pmeth == Py_None) - { - Py_XDECREF(pmeth); - return lldb::ScriptInterpreterObjectSP(); - } - - if (PyCallable_Check(pmeth) == 0) - { - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - Py_XDECREF(pmeth); - return lldb::ScriptInterpreterObjectSP(); - } - - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - Py_XDECREF(pmeth); - - // right now we know this function exists and is callable.. - PyObject* py_return = PyObject_CallMethod(implementor, callee_name, ¶m_format[0], tid, context); - - // if it fails, print the error but otherwise go on - if (PyErr_Occurred()) - { - PyErr_Print(); - PyErr_Clear(); - } - - return MakeScriptObject(py_return); -} - -lldb::ScriptInterpreterObjectSP -ScriptInterpreterPython::CreateScriptedThreadPlan (const char *class_name, - lldb::ThreadPlanSP thread_plan_sp) -{ - if (class_name == nullptr || class_name[0] == '\0') - return lldb::ScriptInterpreterObjectSP(); - - if (!thread_plan_sp.get()) - return lldb::ScriptInterpreterObjectSP(); - - Debugger &debugger = thread_plan_sp->GetTarget().GetDebugger(); - ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter(); - ScriptInterpreterPython *python_interpreter = static_cast(script_interpreter); - - if (!script_interpreter) - return lldb::ScriptInterpreterObjectSP(); - - void* ret_val; - - { - Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - - ret_val = g_swig_thread_plan_script (class_name, - python_interpreter->m_dictionary_name.c_str(), - thread_plan_sp); - } - - return MakeScriptObject(ret_val); -} - -bool -ScriptInterpreterPython::ScriptedThreadPlanExplainsStop (lldb::ScriptInterpreterObjectSP implementor_sp, - Event *event, - bool &script_error) -{ - bool explains_stop = true; - if (implementor_sp) - { - Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - explains_stop = g_swig_call_thread_plan (implementor_sp->GetObject(), "explains_stop", event, script_error); - if (script_error) - return true; - } - return explains_stop; -} - -bool -ScriptInterpreterPython::ScriptedThreadPlanShouldStop (lldb::ScriptInterpreterObjectSP implementor_sp, - Event *event, - bool &script_error) -{ - bool should_stop = true; - if (implementor_sp) - { - Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - should_stop = g_swig_call_thread_plan (implementor_sp->GetObject(), "should_stop", event, script_error); - if (script_error) - return true; - } - return should_stop; -} - -lldb::StateType -ScriptInterpreterPython::ScriptedThreadPlanGetRunState (lldb::ScriptInterpreterObjectSP implementor_sp, - bool &script_error) -{ - bool should_step = false; - if (implementor_sp) - { - Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - should_step = g_swig_call_thread_plan (implementor_sp->GetObject(), "should_step", NULL, script_error); - if (script_error) - should_step = true; - } - if (should_step) - return lldb::eStateStepping; - else - return lldb::eStateRunning; -} - - -lldb::ScriptInterpreterObjectSP -ScriptInterpreterPython::LoadPluginModule (const FileSpec& file_spec, - lldb_private::Error& error) -{ - if (!file_spec.Exists()) - { - error.SetErrorString("no such file"); - return lldb::ScriptInterpreterObjectSP(); - } - - ScriptInterpreterObjectSP module_sp; - - if (LoadScriptingModule(file_spec.GetPath().c_str(),true,true,error,&module_sp)) - return module_sp; - - return lldb::ScriptInterpreterObjectSP(); -} - -lldb::ScriptInterpreterObjectSP -ScriptInterpreterPython::GetDynamicSettings (lldb::ScriptInterpreterObjectSP plugin_module_sp, - Target* target, - const char* setting_name, - lldb_private::Error& error) -{ - if (!plugin_module_sp || !target || !setting_name || !setting_name[0]) - return lldb::ScriptInterpreterObjectSP(); - - if (!g_swig_plugin_get) - return lldb::ScriptInterpreterObjectSP(); - - PyObject *reply_pyobj = nullptr; - - { - 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); - } - - return MakeScriptObject(reply_pyobj); -} - -lldb::ScriptInterpreterObjectSP -ScriptInterpreterPython::CreateSyntheticScriptedProvider (const char *class_name, - lldb::ValueObjectSP valobj) -{ - if (class_name == nullptr || class_name[0] == '\0') - return lldb::ScriptInterpreterObjectSP(); - - if (!valobj.get()) - return lldb::ScriptInterpreterObjectSP(); - - ExecutionContext exe_ctx (valobj->GetExecutionContextRef()); - Target *target = exe_ctx.GetTargetPtr(); - - if (!target) - return lldb::ScriptInterpreterObjectSP(); - - Debugger &debugger = target->GetDebugger(); - ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter(); - ScriptInterpreterPython *python_interpreter = (ScriptInterpreterPython *) script_interpreter; - - if (!script_interpreter) - return lldb::ScriptInterpreterObjectSP(); - - void* ret_val; - - { - 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); - } - - return MakeScriptObject(ret_val); -} - -bool -ScriptInterpreterPython::GenerateTypeScriptFunction (const char* oneliner, std::string& output, const void* name_token) -{ - StringList input; - input.SplitIntoLines(oneliner, strlen(oneliner)); - return GenerateTypeScriptFunction(input, output, name_token); -} - -bool -ScriptInterpreterPython::GenerateTypeSynthClass (const char* oneliner, std::string& output, const void* name_token) -{ - StringList input; - input.SplitIntoLines(oneliner, strlen(oneliner)); - return GenerateTypeSynthClass(input, output, name_token); -} - - -Error -ScriptInterpreterPython::GenerateBreakpointCommandCallbackData (StringList &user_input, std::string& output) -{ - static uint32_t num_created_functions = 0; - user_input.RemoveBlankLines (); - StreamString sstr; - Error error; - if (user_input.GetSize() == 0) - { - error.SetErrorString("No input data."); - return error; - } - - std::string auto_generated_function_name(GenerateUniqueName("lldb_autogen_python_bp_callback_func_",num_created_functions)); - sstr.Printf ("def %s (frame, bp_loc, internal_dict):", auto_generated_function_name.c_str()); - - error = GenerateFunction(sstr.GetData(), user_input); - if (!error.Success()) - return error; - - // Store the name of the auto-generated function to be called. - output.assign(auto_generated_function_name); - return error; -} - -bool -ScriptInterpreterPython::GenerateWatchpointCommandCallbackData (StringList &user_input, std::string& output) -{ - static uint32_t num_created_functions = 0; - user_input.RemoveBlankLines (); - StreamString sstr; - - if (user_input.GetSize() == 0) - return false; - - std::string auto_generated_function_name(GenerateUniqueName("lldb_autogen_python_wp_callback_func_",num_created_functions)); - sstr.Printf ("def %s (frame, wp, internal_dict):", auto_generated_function_name.c_str()); - - if (!GenerateFunction(sstr.GetData(), user_input).Success()) - return false; - - // Store the name of the auto-generated function to be called. - output.assign(auto_generated_function_name); - return true; -} - -bool -ScriptInterpreterPython::GetScriptedSummary (const char *python_function_name, - lldb::ValueObjectSP valobj, - lldb::ScriptInterpreterObjectSP& callee_wrapper_sp, - const TypeSummaryOptions& options, - std::string& retval) -{ - - Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__); - - if (!valobj.get()) - { - retval.assign(""); - return false; - } - - void* old_callee = (callee_wrapper_sp ? callee_wrapper_sp->GetObject() : nullptr); - void* new_callee = old_callee; - - bool ret_val; - if (python_function_name - && *python_function_name) - { - { - Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - { - TypeSummaryOptionsSP options_sp(new TypeSummaryOptions(options)); - - 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, - options_sp, - retval); - } - } - } - else - { - retval.assign(""); - return false; - } - - if (new_callee && old_callee != new_callee) - callee_wrapper_sp = MakeScriptObject(new_callee); - - return ret_val; - -} - -void -ScriptInterpreterPython::Clear () -{ - // Release any global variables that might have strong references to - // LLDB objects when clearing the python script interpreter. - Locker locker(this, - ScriptInterpreterPython::Locker::AcquireLock, - ScriptInterpreterPython::Locker::FreeAcquiredLock); - - // This may be called as part of Py_Finalize. In that case the modules are destroyed in random - // order and we can't guarantee that we can access these. - if (Py_IsInitialized()) - PyRun_SimpleString("lldb.debugger = None; lldb.target = None; lldb.process = None; lldb.thread = None; lldb.frame = None"); -} - -bool -ScriptInterpreterPython::BreakpointCallbackFunction -( - void *baton, - StoppointCallbackContext *context, - user_id_t break_id, - user_id_t break_loc_id -) -{ - BreakpointOptions::CommandData *bp_option_data = (BreakpointOptions::CommandData *) baton; - const char *python_function_name = bp_option_data->script_source.c_str(); - - if (!context) - return true; - - ExecutionContext exe_ctx (context->exe_ctx_ref); - Target *target = exe_ctx.GetTargetPtr(); - - if (!target) - return true; - - Debugger &debugger = target->GetDebugger(); - ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter(); - ScriptInterpreterPython *python_interpreter = (ScriptInterpreterPython *) script_interpreter; - - if (!script_interpreter) - return true; - - if (python_function_name && python_function_name[0]) - { - const StackFrameSP stop_frame_sp (exe_ctx.GetFrameSP()); - BreakpointSP breakpoint_sp = target->GetBreakpointByID (break_id); - if (breakpoint_sp) - { - const BreakpointLocationSP bp_loc_sp (breakpoint_sp->FindLocationByID (break_loc_id)); - - if (stop_frame_sp && bp_loc_sp) - { - bool ret_val = true; - { - 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); - } - return ret_val; - } - } - } - // We currently always true so we stop in case anything goes wrong when - // trying to call the script function - return true; -} - -bool -ScriptInterpreterPython::WatchpointCallbackFunction -( - void *baton, - StoppointCallbackContext *context, - user_id_t watch_id -) -{ - WatchpointOptions::CommandData *wp_option_data = (WatchpointOptions::CommandData *) baton; - const char *python_function_name = wp_option_data->script_source.c_str(); - - if (!context) - return true; - - ExecutionContext exe_ctx (context->exe_ctx_ref); - Target *target = exe_ctx.GetTargetPtr(); - - if (!target) - return true; - - Debugger &debugger = target->GetDebugger(); - ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter(); - ScriptInterpreterPython *python_interpreter = (ScriptInterpreterPython *) script_interpreter; - - if (!script_interpreter) - return true; - - if (python_function_name && python_function_name[0]) - { - const StackFrameSP stop_frame_sp (exe_ctx.GetFrameSP()); - WatchpointSP wp_sp = target->GetWatchpointList().FindByID (watch_id); - if (wp_sp) - { - if (stop_frame_sp && wp_sp) - { - bool ret_val = true; - { - 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); - } - return ret_val; - } - } - } - // We currently always true so we stop in case anything goes wrong when - // trying to call the script function - return true; -} - -size_t -ScriptInterpreterPython::CalculateNumChildren (const lldb::ScriptInterpreterObjectSP& implementor_sp) -{ - if (!implementor_sp) - return 0; - - void* implementor = implementor_sp->GetObject(); - - if (!implementor) - return 0; - - if (!g_swig_calc_children) - return 0; - - uint32_t ret_val = 0; - - { - Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - ret_val = g_swig_calc_children (implementor); - } - - return ret_val; -} - -lldb::ValueObjectSP -ScriptInterpreterPython::GetChildAtIndex (const lldb::ScriptInterpreterObjectSP& implementor_sp, uint32_t idx) -{ - if (!implementor_sp) - return lldb::ValueObjectSP(); - - void* implementor = implementor_sp->GetObject(); - - if (!implementor) - return lldb::ValueObjectSP(); - - if (!g_swig_get_child_index || !g_swig_cast_to_sbvalue) - return lldb::ValueObjectSP(); - - lldb::ValueObjectSP ret_val; - - { - Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - void* child_ptr = g_swig_get_child_index (implementor,idx); - if (child_ptr != nullptr && child_ptr != Py_None) - { - lldb::SBValue* sb_value_ptr = (lldb::SBValue*)g_swig_cast_to_sbvalue(child_ptr); - if (sb_value_ptr == nullptr) - Py_XDECREF(child_ptr); - else - ret_val = g_swig_get_valobj_sp_from_sbvalue (sb_value_ptr); - } - else - { - Py_XDECREF(child_ptr); - } - } - - return ret_val; -} - -int -ScriptInterpreterPython::GetIndexOfChildWithName (const lldb::ScriptInterpreterObjectSP& implementor_sp, const char* child_name) -{ - if (!implementor_sp) - return UINT32_MAX; - - void* implementor = implementor_sp->GetObject(); - - if (!implementor) - return UINT32_MAX; - - if (!g_swig_get_index_child) - return UINT32_MAX; - - int ret_val = UINT32_MAX; - - { - Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - ret_val = g_swig_get_index_child (implementor, child_name); - } - - return ret_val; -} - -bool -ScriptInterpreterPython::UpdateSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor_sp) -{ - bool ret_val = false; - - if (!implementor_sp) - return ret_val; - - void* implementor = implementor_sp->GetObject(); - - if (!implementor) - return ret_val; - - if (!g_swig_update_provider) - return ret_val; - - { - Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - ret_val = g_swig_update_provider (implementor); - } - - return ret_val; -} - -bool -ScriptInterpreterPython::MightHaveChildrenSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor_sp) -{ - bool ret_val = false; - - if (!implementor_sp) - return ret_val; - - void* implementor = implementor_sp->GetObject(); - - if (!implementor) - return ret_val; - - if (!g_swig_mighthavechildren_provider) - return ret_val; - - { - Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - ret_val = g_swig_mighthavechildren_provider (implementor); - } - - return ret_val; -} - -lldb::ValueObjectSP -ScriptInterpreterPython::GetSyntheticValue (const lldb::ScriptInterpreterObjectSP& implementor_sp) -{ - lldb::ValueObjectSP ret_val(nullptr); - - if (!implementor_sp) - return ret_val; - - void* implementor = implementor_sp->GetObject(); - - if (!implementor) - return ret_val; - - if (!g_swig_getvalue_provider || !g_swig_cast_to_sbvalue || !g_swig_get_valobj_sp_from_sbvalue) - return ret_val; - - { - Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - void* child_ptr = g_swig_getvalue_provider (implementor); - if (child_ptr != nullptr && child_ptr != Py_None) - { - lldb::SBValue* sb_value_ptr = (lldb::SBValue*)g_swig_cast_to_sbvalue(child_ptr); - if (sb_value_ptr == nullptr) - Py_XDECREF(child_ptr); - else - ret_val = g_swig_get_valobj_sp_from_sbvalue (sb_value_ptr); - } - else - { - Py_XDECREF(child_ptr); - } - } - - return ret_val; -} - -static std::string -ReadPythonBacktrace (PyObject* py_backtrace) -{ - PyObject* traceback_module = nullptr, - *stringIO_module = nullptr, - *stringIO_builder = nullptr, - *stringIO_buffer = nullptr, - *printTB = nullptr, - *printTB_args = nullptr, - *printTB_result = nullptr, - *stringIO_getvalue = nullptr, - *printTB_string = nullptr; - - std::string retval("backtrace unavailable"); - - if (py_backtrace && py_backtrace != Py_None) - { - traceback_module = PyImport_ImportModule("traceback"); - stringIO_module = PyImport_ImportModule("StringIO"); - - if (traceback_module && traceback_module != Py_None && stringIO_module && stringIO_module != Py_None) - { - stringIO_builder = PyObject_GetAttrString(stringIO_module, "StringIO"); - if (stringIO_builder && stringIO_builder != Py_None) - { - stringIO_buffer = PyObject_CallObject(stringIO_builder, nullptr); - if (stringIO_buffer && stringIO_buffer != Py_None) - { - printTB = PyObject_GetAttrString(traceback_module, "print_tb"); - if (printTB && printTB != Py_None) - { - printTB_args = Py_BuildValue("OOO",py_backtrace,Py_None,stringIO_buffer); - printTB_result = PyObject_CallObject(printTB, printTB_args); - stringIO_getvalue = PyObject_GetAttrString(stringIO_buffer, "getvalue"); - if (stringIO_getvalue && stringIO_getvalue != Py_None) - { - printTB_string = PyObject_CallObject (stringIO_getvalue,nullptr); - if (printTB_string && printTB_string != Py_None && PyString_Check(printTB_string)) - retval.assign(PyString_AsString(printTB_string)); - } - } - } - } - } - } - Py_XDECREF(traceback_module); - Py_XDECREF(stringIO_module); - Py_XDECREF(stringIO_builder); - Py_XDECREF(stringIO_buffer); - Py_XDECREF(printTB); - Py_XDECREF(printTB_args); - Py_XDECREF(printTB_result); - Py_XDECREF(stringIO_getvalue); - Py_XDECREF(printTB_string); - return retval; -} - -bool -ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function, - Process* process, - std::string& output, - Error& error) -{ - bool ret_val; - if (!process) - { - error.SetErrorString("no process"); - return false; - } - if (!impl_function || !impl_function[0]) - { - error.SetErrorString("no function to execute"); - return false; - } - if (!g_swig_run_script_keyword_process) - { - error.SetErrorString("internal helper function missing"); - return false; - } - { - ProcessSP process_sp(process->shared_from_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"); - } - return ret_val; -} - -bool -ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function, - Thread* thread, - std::string& output, - Error& error) -{ - bool ret_val; - if (!thread) - { - error.SetErrorString("no thread"); - return false; - } - if (!impl_function || !impl_function[0]) - { - error.SetErrorString("no function to execute"); - return false; - } - if (!g_swig_run_script_keyword_thread) - { - error.SetErrorString("internal helper function missing"); - return false; - } - { - ThreadSP thread_sp(thread->shared_from_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"); - } - return ret_val; -} - -bool -ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function, - Target* target, - std::string& output, - Error& error) -{ - bool ret_val; - if (!target) - { - error.SetErrorString("no thread"); - return false; - } - if (!impl_function || !impl_function[0]) - { - error.SetErrorString("no function to execute"); - return false; - } - if (!g_swig_run_script_keyword_target) - { - error.SetErrorString("internal helper function missing"); - return false; - } - { - TargetSP target_sp(target->shared_from_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"); - } - return ret_val; -} - -bool -ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function, - StackFrame* frame, - std::string& output, - Error& error) -{ - bool ret_val; - if (!frame) - { - error.SetErrorString("no frame"); - return false; - } - if (!impl_function || !impl_function[0]) - { - error.SetErrorString("no function to execute"); - return false; - } - if (!g_swig_run_script_keyword_frame) - { - error.SetErrorString("internal helper function missing"); - return false; - } - { - StackFrameSP frame_sp(frame->shared_from_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"); - } - return ret_val; -} - -bool -ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function, - ValueObject *value, - std::string& output, - Error& error) -{ - bool ret_val; - if (!value) - { - error.SetErrorString("no value"); - return false; - } - if (!impl_function || !impl_function[0]) - { - error.SetErrorString("no function to execute"); - return false; - } - if (!g_swig_run_script_keyword_value) - { - error.SetErrorString("internal helper function missing"); - return false; - } - { - ValueObjectSP value_sp(value->GetSP()); - Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - ret_val = g_swig_run_script_keyword_value (impl_function, m_dictionary_name.c_str(), value_sp, output); - if (!ret_val) - error.SetErrorString("python script evaluation failed"); - } - return ret_val; -} - -uint64_t replace_all(std::string& str, const std::string& oldStr, const std::string& newStr) -{ - size_t pos = 0; - uint64_t matches = 0; - while((pos = str.find(oldStr, pos)) != std::string::npos) - { - matches++; - str.replace(pos, oldStr.length(), newStr); - pos += newStr.length(); - } - return matches; -} - -bool -ScriptInterpreterPython::LoadScriptingModule (const char* pathname, - bool can_reload, - bool init_session, - lldb_private::Error& error, - lldb::ScriptInterpreterObjectSP* module_sp) -{ - if (!pathname || !pathname[0]) - { - error.SetErrorString("invalid pathname"); - return false; - } - - if (!g_swig_call_module_init) - { - error.SetErrorString("internal helper function missing"); - return false; - } - - lldb::DebuggerSP debugger_sp = m_interpreter.GetDebugger().shared_from_this(); - - { - FileSpec target_file(pathname, true); - std::string basename(target_file.GetFilename().GetCString()); - - StreamString command_stream; - - // Before executing Pyton code, lock the GIL. - Locker py_lock (this, - Locker::AcquireLock | (init_session ? Locker::InitSession : 0) | Locker::NoSTDIN, - Locker::FreeAcquiredLock | (init_session ? Locker::TearDownSession : 0)); - - if (target_file.GetFileType() == FileSpec::eFileTypeInvalid || - target_file.GetFileType() == FileSpec::eFileTypeUnknown) - { - // if not a valid file of any sort, check if it might be a filename still - // dot can't be used but / and \ can, and if either is found, reject - if (strchr(pathname,'\\') || strchr(pathname,'/')) - { - error.SetErrorString("invalid pathname"); - return false; - } - basename = pathname; // not a filename, probably a package of some sort, let it go through - } - else if (target_file.GetFileType() == FileSpec::eFileTypeDirectory || - target_file.GetFileType() == FileSpec::eFileTypeRegular || - target_file.GetFileType() == FileSpec::eFileTypeSymbolicLink) - { - std::string directory(target_file.GetDirectory().GetCString()); - replace_all(directory,"'","\\'"); - - // now make sure that Python has "directory" in the search path - StreamString command_stream; - 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)).Success(); - if (!syspath_retval) - { - error.SetErrorString("Python sys.path handling failed"); - return false; - } - - // strip .py or .pyc extension - ConstString extension = target_file.GetFileNameExtension(); - if (extension) - { - if (::strcmp(extension.GetCString(), "py") == 0) - basename.resize(basename.length()-3); - else if(::strcmp(extension.GetCString(), "pyc") == 0) - basename.resize(basename.length()-4); - } - } - else - { - error.SetErrorString("no known way to import this module specification"); - return false; - } - - // check if the module is already import-ed - command_stream.Clear(); - command_stream.Printf("sys.modules.__contains__('%s')",basename.c_str()); - bool does_contain = false; - // 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(), - ScriptInterpreterPython::eScriptReturnTypeBool, - &does_contain, - ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false).SetSetLLDBGlobals(false)) && does_contain); - // 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 = !(GetSessionDictionary().GetItemForKey(basename.c_str()).IsNULLOrNone()); - - bool was_imported = (was_imported_globally || was_imported_locally); - - if (was_imported == true && can_reload == false) - { - error.SetErrorString("module already imported"); - return false; - } - - // now actually do the import - command_stream.Clear(); - - if (was_imported) - { - if (!was_imported_locally) - command_stream.Printf("import %s ; reload(%s)",basename.c_str(),basename.c_str()); - else - command_stream.Printf("reload(%s)",basename.c_str()); - } - else - command_stream.Printf("import %s",basename.c_str()); - - 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) - if (!g_swig_call_module_init (basename.c_str(), - m_dictionary_name.c_str(), - debugger_sp)) - { - error.SetErrorString("calling __lldb_init_module failed"); - return false; - } - - if (module_sp) - { - // everything went just great, now set the module object - command_stream.Clear(); - command_stream.Printf("%s",basename.c_str()); - void* module_pyobj = nullptr; - if (ExecuteOneLineWithReturn(command_stream.GetData(),ScriptInterpreter::eScriptReturnTypeOpaqueObject,&module_pyobj) && module_pyobj) - *module_sp = MakeScriptObject(module_pyobj); - } - - return true; - } -} - -bool -ScriptInterpreterPython::IsReservedWord (const char* word) -{ - StreamString command_stream; - command_stream.Printf("keyword.iskeyword('%s')", word); - bool result; - ExecuteScriptOptions options; - options.SetEnableIO(false); - options.SetMaskoutErrors(true); - options.SetSetLLDBGlobals(false); - if (ExecuteOneLineWithReturn(command_stream.GetData(), ScriptInterpreter::eScriptReturnTypeBool, &result, options)) - return result; - return false; -} - -lldb::ScriptInterpreterObjectSP -ScriptInterpreterPython::MakeScriptObject (void* object) -{ - return lldb::ScriptInterpreterObjectSP(new ScriptInterpreterPythonObject(object)); -} - -ScriptInterpreterPython::SynchronicityHandler::SynchronicityHandler (lldb::DebuggerSP debugger_sp, - ScriptedCommandSynchronicity synchro) : - m_debugger_sp(debugger_sp), - m_synch_wanted(synchro), - m_old_asynch(debugger_sp->GetAsyncExecution()) -{ - if (m_synch_wanted == eScriptedCommandSynchronicitySynchronous) - m_debugger_sp->SetAsyncExecution(false); - else if (m_synch_wanted == eScriptedCommandSynchronicityAsynchronous) - m_debugger_sp->SetAsyncExecution(true); -} - -ScriptInterpreterPython::SynchronicityHandler::~SynchronicityHandler() -{ - if (m_synch_wanted != eScriptedCommandSynchronicityCurrentValue) - m_debugger_sp->SetAsyncExecution(m_old_asynch); -} - -bool -ScriptInterpreterPython::RunScriptBasedCommand(const char* impl_function, - const char* args, - ScriptedCommandSynchronicity synchronicity, - lldb_private::CommandReturnObject& cmd_retobj, - Error& error, - const lldb_private::ExecutionContext& exe_ctx) -{ - if (!impl_function) - { - error.SetErrorString("no function to execute"); - return false; - } - - if (!g_swig_call_command) - { - error.SetErrorString("no helper function to run scripted commands"); - return false; - } - - lldb::DebuggerSP debugger_sp = m_interpreter.GetDebugger().shared_from_this(); - lldb::ExecutionContextRefSP exe_ctx_ref_sp(new ExecutionContextRef(exe_ctx)); - - if (!debugger_sp.get()) - { - error.SetErrorString("invalid Debugger pointer"); - return false; - } - - bool ret_val = false; - - std::string err_msg; - - { - Locker py_lock(this, - Locker::AcquireLock | Locker::InitSession | (cmd_retobj.GetInteractive() ? 0 : Locker::NoSTDIN), - Locker::FreeLock | Locker::TearDownSession); - - SynchronicityHandler synch_handler(debugger_sp, - synchronicity); - - ret_val = g_swig_call_command (impl_function, - m_dictionary_name.c_str(), - debugger_sp, - args, - cmd_retobj, - exe_ctx_ref_sp); - } - - if (!ret_val) - error.SetErrorString("unable to execute script function"); - else - error.Clear(); - - return ret_val; -} - -// in Python, a special attribute __doc__ contains the docstring -// for an object (function, method, class, ...) if any is defined -// Otherwise, the attribute's value is None -bool -ScriptInterpreterPython::GetDocumentationForItem(const char* item, std::string& dest) -{ - dest.clear(); - if (!item || !*item) - return false; - std::string command(item); - command += ".__doc__"; - - char* result_ptr = nullptr; // Python is going to point this to valid data if ExecuteOneLineWithReturn returns successfully - - if (ExecuteOneLineWithReturn (command.c_str(), - ScriptInterpreter::eScriptReturnTypeCharStrOrNone, - &result_ptr, - ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false))) - { - if (result_ptr) - dest.assign(result_ptr); - return true; - } - else - { - StreamString str_stream; - str_stream.Printf("Function %s was not found. Containing module might be missing.",item); - dest.assign(str_stream.GetData()); - return false; - } -} - -std::unique_ptr -ScriptInterpreterPython::AcquireInterpreterLock () -{ - std::unique_ptr py_lock(new Locker(this, - Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN, - Locker::FreeLock | Locker::TearDownSession)); - return py_lock; -} - -void -ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback swig_init_callback, - SWIGBreakpointCallbackFunction swig_breakpoint_callback, - SWIGWatchpointCallbackFunction swig_watchpoint_callback, - SWIGPythonTypeScriptCallbackFunction swig_typescript_callback, - SWIGPythonCreateSyntheticProvider swig_synthetic_script, - SWIGPythonCalculateNumChildren swig_calc_children, - SWIGPythonGetChildAtIndex swig_get_child_index, - SWIGPythonGetIndexOfChildWithName swig_get_index_child, - SWIGPythonCastPyObjectToSBValue swig_cast_to_sbvalue , - SWIGPythonGetValueObjectSPFromSBValue swig_get_valobj_sp_from_sbvalue, - SWIGPythonUpdateSynthProviderInstance swig_update_provider, - SWIGPythonMightHaveChildrenSynthProviderInstance swig_mighthavechildren_provider, - SWIGPythonGetValueSynthProviderInstance swig_getvalue_provider, - SWIGPythonCallCommand swig_call_command, - SWIGPythonCallModuleInit swig_call_module_init, - SWIGPythonCreateOSPlugin swig_create_os_plugin, - SWIGPythonScriptKeyword_Process swig_run_script_keyword_process, - SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread, - SWIGPythonScriptKeyword_Target swig_run_script_keyword_target, - SWIGPythonScriptKeyword_Frame swig_run_script_keyword_frame, - SWIGPythonScriptKeyword_Value swig_run_script_keyword_value, - SWIGPython_GetDynamicSetting swig_plugin_get, - SWIGPythonCreateScriptedThreadPlan swig_thread_plan_script, - SWIGPythonCallThreadPlan swig_call_thread_plan) -{ - g_swig_init_callback = swig_init_callback; - g_swig_breakpoint_callback = swig_breakpoint_callback; - g_swig_watchpoint_callback = swig_watchpoint_callback; - g_swig_typescript_callback = swig_typescript_callback; - g_swig_synthetic_script = swig_synthetic_script; - g_swig_calc_children = swig_calc_children; - g_swig_get_child_index = swig_get_child_index; - g_swig_get_index_child = swig_get_index_child; - g_swig_cast_to_sbvalue = swig_cast_to_sbvalue; - g_swig_get_valobj_sp_from_sbvalue = swig_get_valobj_sp_from_sbvalue; - g_swig_update_provider = swig_update_provider; - g_swig_mighthavechildren_provider = swig_mighthavechildren_provider; - g_swig_getvalue_provider = swig_getvalue_provider; - g_swig_call_command = swig_call_command; - g_swig_call_module_init = swig_call_module_init; - g_swig_create_os_plugin = swig_create_os_plugin; - g_swig_run_script_keyword_process = swig_run_script_keyword_process; - g_swig_run_script_keyword_thread = swig_run_script_keyword_thread; - g_swig_run_script_keyword_target = swig_run_script_keyword_target; - g_swig_run_script_keyword_frame = swig_run_script_keyword_frame; - g_swig_run_script_keyword_value = swig_run_script_keyword_value; - g_swig_plugin_get = swig_plugin_get; - g_swig_thread_plan_script = swig_thread_plan_script; - g_swig_call_thread_plan = swig_call_thread_plan; -} - -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 - // settings so we can restore them. - TerminalState stdin_tty_state; - stdin_tty_state.Save(STDIN_FILENO, false); - - PyGILState_STATE gstate; - Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT | LIBLLDB_LOG_VERBOSE)); - bool threads_already_initialized = false; - if (PyEval_ThreadsInitialized ()) { - gstate = PyGILState_Ensure (); - if (log) - log->Printf("Ensured PyGILState. Previous state = %slocked\n", gstate == PyGILState_UNLOCKED ? "un" : ""); - threads_already_initialized = true; - } else { - // InitThreads acquires the GIL if it hasn't been called before. - PyEval_InitThreads (); - } - Py_InitializeEx (0); - - // Initialize SWIG after setting up python - if (g_swig_init_callback) - g_swig_init_callback (); - - // Update the path python uses to search for modules to include the current directory. - - PyRun_SimpleString ("import sys"); - PyRun_SimpleString ("sys.path.append ('.')"); - - // Find the module that owns this code and use that path we get to - // set the sys.path appropriately. - - FileSpec file_spec; - char python_dir_path[PATH_MAX]; - if (HostInfo::GetLLDBPath(ePathTypePythonDir, file_spec)) - { - std::string python_path("sys.path.insert(0,\""); - size_t orig_len = python_path.length(); - if (file_spec.GetPath(python_dir_path, sizeof (python_dir_path))) - { - python_path.append (python_dir_path); - python_path.append ("\")"); - PyRun_SimpleString (python_path.c_str()); - python_path.resize (orig_len); - } - - if (HostInfo::GetLLDBPath(ePathTypeLLDBShlibDir, file_spec)) - { - if (file_spec.GetPath(python_dir_path, sizeof (python_dir_path))) - { - python_path.append (python_dir_path); - python_path.append ("\")"); - PyRun_SimpleString (python_path.c_str()); - python_path.resize (orig_len); - } - } - } - - // Importing 'lldb' module calls SBDebugger::Initialize, which calls Debugger::Initialize, which increments a - // global debugger ref-count; therefore we need to check the ref-count before and after importing lldb, and if the - // ref-count increased we need to call Debugger::Terminate here to decrement the ref-count so that when the final - // call to Debugger::Terminate is made, the ref-count has the correct value. - - int old_count = Debugger::TestDebuggerRefCount (); - - PyRun_SimpleString ("sys.dont_write_bytecode = 1; import lldb.embedded_interpreter; from lldb.embedded_interpreter import run_python_interpreter; from lldb.embedded_interpreter import run_one_line"); - - int new_count = Debugger::TestDebuggerRefCount (); - - if (new_count > old_count) - Debugger::Terminate (); - - if (threads_already_initialized) { - if (log) - log->Printf("Releasing PyGILState. Returning to state = %slocked\n", gstate == PyGILState_UNLOCKED ? "un" : ""); - PyGILState_Release (gstate); - } else { - // We initialized the threads in this function, just unlock the GIL. - PyEval_SaveThread(); - } - - stdin_tty_state.Restore(); -} - -//void -//ScriptInterpreterPython::Terminate () -//{ -// // We are intentionally NOT calling Py_Finalize here (this would be the logical place to call it). Calling -// // Py_Finalize here causes test suite runs to seg fault: The test suite runs in Python. It registers -// // SBDebugger::Terminate to be called 'at_exit'. When the test suite Python harness finishes up, it calls -// // Py_Finalize, which calls all the 'at_exit' registered functions. SBDebugger::Terminate calls Debugger::Terminate, -// // which calls lldb::Terminate, which calls ScriptInterpreter::Terminate, which calls -// // ScriptInterpreterPython::Terminate. So if we call Py_Finalize here, we end up with Py_Finalize being called from -// // within Py_Finalize, which results in a seg fault. -// // -// // Since this function only gets called when lldb is shutting down and going away anyway, the fact that we don't -// // actually call Py_Finalize should not cause any problems (everything should shut down/go away anyway when the -// // process exits). -// // -//// Py_Finalize (); -//} - -#endif // #ifdef LLDB_DISABLE_PYTHON Index: source/Interpreter/embedded_interpreter.py =================================================================== --- source/Interpreter/embedded_interpreter.py +++ /dev/null @@ -1,112 +0,0 @@ -import __builtin__ -import code -import lldb -import sys -import traceback - -try: - import readline - import rlcompleter -except ImportError: - have_readline = False -except AttributeError: - # This exception gets hit by the rlcompleter when Linux is using - # the readline suppression import. - 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') - -g_builtin_override_called = False - -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 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') - -# 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 - -g_run_one_line_str = None - - -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 readfunc_stdio(prompt): - sys.stdout.write(prompt) - return sys.stdin.readline().rstrip() - -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) Index: source/Plugins/OperatingSystem/Python/OperatingSystemPython.h =================================================================== --- source/Plugins/OperatingSystem/Python/OperatingSystemPython.h +++ source/Plugins/OperatingSystem/Python/OperatingSystemPython.h @@ -14,7 +14,7 @@ // C Includes // C++ Includes // Other libraries and framework includes -#include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/ScriptInterpreter/ScriptInterpreter.h" #include "lldb/Target/OperatingSystem.h" class DynamicRegisterInfo; Index: source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp =================================================================== --- source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp +++ source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp @@ -24,7 +24,7 @@ #include "lldb/Core/StreamString.h" #include "lldb/Core/ValueObjectVariable.h" #include "lldb/Interpreter/CommandInterpreter.h" -#include "lldb/Interpreter/PythonDataObjects.h" +#include "lldb/ScriptInterpreter/Python/PythonDataObjects.h" #include "lldb/Symbol/ClangNamespaceDecl.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/VariableList.h" Index: source/Plugins/Process/Utility/DynamicRegisterInfo.cpp =================================================================== --- source/Plugins/Process/Utility/DynamicRegisterInfo.cpp +++ source/Plugins/Process/Utility/DynamicRegisterInfo.cpp @@ -21,7 +21,7 @@ #include "lldb/DataFormatters/FormatManager.h" #ifndef LLDB_DISABLE_PYTHON -#include "lldb/Interpreter/PythonDataObjects.h" +#include "lldb/ScriptInterpreter/Python/PythonDataObjects.h" #endif using namespace lldb; Index: source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -17,9 +17,6 @@ #include "lldb/Core/RegisterValue.h" #include "lldb/Core/Scalar.h" #include "lldb/Core/StreamString.h" -#ifndef LLDB_DISABLE_PYTHON -#include "lldb/Interpreter/PythonDataObjects.h" -#endif #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Target.h" #include "lldb/Utility/Utils.h" Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -51,7 +51,7 @@ #include "lldb/Interpreter/CommandObjectMultiword.h" #include "lldb/Interpreter/CommandReturnObject.h" #ifndef LLDB_DISABLE_PYTHON -#include "lldb/Interpreter/PythonDataObjects.h" +#include "lldb/ScriptInterpreter/Python/PythonDataObjects.h" #endif #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/DynamicLoader.h" Index: source/ScriptInterpreter/CMakeLists.txt =================================================================== --- /dev/null +++ source/ScriptInterpreter/CMakeLists.txt @@ -0,0 +1,9 @@ + +add_lldb_library(lldbScriptInterpreter + ScriptInterpreter.cpp + ScriptInterpreterNone.cpp + ) + +if (NOT LLDB_DISABLE_PYTHON) + add_subdirectory(Python) +endif() Index: source/ScriptInterpreter/Python/CMakeLists.txt =================================================================== --- /dev/null +++ source/ScriptInterpreter/Python/CMakeLists.txt @@ -0,0 +1,6 @@ + +add_lldb_library(lldbPythonInterpreter + PythonDataObjects.cpp + ScriptInterpreterPython.cpp + ) + \ No newline at end of file Index: source/ScriptInterpreter/Python/PythonDataObjects.cpp =================================================================== --- /dev/null +++ source/ScriptInterpreter/Python/PythonDataObjects.cpp @@ -0,0 +1,459 @@ +//===-- PythonDataObjects.cpp ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// In order to guarantee correct working with Python, Python.h *MUST* be +// the *FIRST* header file included here. +#ifdef LLDB_DISABLE_PYTHON + +// Python is disabled in this build + +#else + +#include "lldb/lldb-python.h" + +#include + +#include "lldb/Core/Stream.h" +#include "lldb/Host/File.h" +#include "lldb/ScriptInterpreter/Python/PythonDataObjects.h" +#include "lldb/ScriptInterpreter/ScriptInterpreter.h" + +using namespace lldb_private; +using namespace lldb; + +//---------------------------------------------------------------------- +// PythonObject +//---------------------------------------------------------------------- +PythonObject::PythonObject(const lldb::ScriptInterpreterObjectSP &script_object_sp) + : m_py_obj(nullptr) +{ + if (script_object_sp) + Reset((PyObject *)script_object_sp->GetObject()); +} + +void +PythonObject::Dump(Stream &strm) const +{ + if (m_py_obj) + { + FILE *file = ::tmpfile(); + if (file) + { + ::PyObject_Print(m_py_obj, file, 0); + const long length = ftell(file); + if (length) + { + ::rewind(file); + std::vector file_contents(length, '\0'); + const size_t length_read = ::fread(file_contents.data(), 1, file_contents.size(), file); + if (length_read > 0) + strm.Write(file_contents.data(), length_read); + } + ::fclose(file); + } + } + else + strm.PutCString("NULL"); +} + +PythonString +PythonObject::Repr() +{ + if (!m_py_obj) + return PythonString(); + PyObject *repr = PyObject_Repr(m_py_obj); + if (!repr) + return PythonString(); + return PythonString(repr); +} + +PythonString +PythonObject::Str() +{ + if (!m_py_obj) + return PythonString(); + PyObject *str = PyObject_Str(m_py_obj); + if (!str) + return PythonString(); + return PythonString(str); +} + +bool +PythonObject::IsNULLOrNone() const +{ + return ((m_py_obj == nullptr) || (m_py_obj == Py_None)); +} + +//---------------------------------------------------------------------- +// PythonString +//---------------------------------------------------------------------- + +PythonString::PythonString(PyObject *py_obj) + : PythonObject() +{ + Reset(py_obj); // Use "Reset()" to ensure that py_obj is a string +} + +PythonString::PythonString(const PythonObject &object) + : PythonObject() +{ + Reset(object.get()); // Use "Reset()" to ensure that py_obj is a string +} + +PythonString::PythonString(const lldb::ScriptInterpreterObjectSP &script_object_sp) + : PythonObject() +{ + if (script_object_sp) + Reset((PyObject *)script_object_sp->GetObject()); // Use "Reset()" to ensure that py_obj is a string +} + +PythonString::PythonString(const char *string) + : PythonObject(PyString_FromString(string)) +{ +} + +PythonString::PythonString() + : PythonObject() +{ +} + +PythonString::~PythonString() +{ +} + +bool +PythonString::Reset(PyObject *py_obj) +{ + if (py_obj && PyString_Check(py_obj)) + return PythonObject::Reset(py_obj); + + PythonObject::Reset(nullptr); + return py_obj == nullptr; +} + +const char * +PythonString::GetString() const +{ + if (m_py_obj) + return PyString_AsString(m_py_obj); + return nullptr; +} + +size_t +PythonString::GetSize() const +{ + if (m_py_obj) + return PyString_Size(m_py_obj); + return 0; +} + +void +PythonString::SetString(const char *string) +{ + PythonObject::Reset(PyString_FromString(string)); +} + +//---------------------------------------------------------------------- +// PythonInteger +//---------------------------------------------------------------------- + +PythonInteger::PythonInteger(PyObject *py_obj) + : PythonObject() +{ + Reset(py_obj); // Use "Reset()" to ensure that py_obj is a integer type +} + +PythonInteger::PythonInteger(const PythonObject &object) + : PythonObject() +{ + Reset(object.get()); // Use "Reset()" to ensure that py_obj is a integer type +} + +PythonInteger::PythonInteger(const lldb::ScriptInterpreterObjectSP &script_object_sp) + : PythonObject() +{ + if (script_object_sp) + Reset((PyObject *)script_object_sp->GetObject()); // Use "Reset()" to ensure that py_obj is a string +} + +PythonInteger::PythonInteger(int64_t value) + : PythonObject() +{ + SetInteger(value); +} + +PythonInteger::~PythonInteger() +{ +} + +bool +PythonInteger::Reset(PyObject *py_obj) +{ + if (py_obj) + { + if (PyInt_Check(py_obj) || PyLong_Check(py_obj)) + return PythonObject::Reset(py_obj); + } + + PythonObject::Reset(nullptr); + return py_obj == nullptr; +} + +int64_t +PythonInteger::GetInteger() +{ + if (m_py_obj) + { + if (PyInt_Check(m_py_obj)) + return PyInt_AsLong(m_py_obj); + else if (PyLong_Check(m_py_obj)) + return PyLong_AsLongLong(m_py_obj); + } + return UINT64_MAX; +} + +void +PythonInteger::SetInteger(int64_t value) +{ + PythonObject::Reset(PyLong_FromLongLong(value)); +} + +//---------------------------------------------------------------------- +// PythonList +//---------------------------------------------------------------------- + +PythonList::PythonList(bool create_empty) + : PythonObject(create_empty ? PyList_New(0) : nullptr) +{ +} + +PythonList::PythonList(uint32_t count) + : PythonObject(PyList_New(count)) +{ +} + +PythonList::PythonList(PyObject *py_obj) + : PythonObject() +{ + Reset(py_obj); // Use "Reset()" to ensure that py_obj is a list +} + +PythonList::PythonList(const PythonObject &object) + : PythonObject() +{ + Reset(object.get()); // Use "Reset()" to ensure that py_obj is a list +} + +PythonList::PythonList(const lldb::ScriptInterpreterObjectSP &script_object_sp) + : PythonObject() +{ + if (script_object_sp) + Reset((PyObject *)script_object_sp->GetObject()); // Use "Reset()" to ensure that py_obj is a list +} + +PythonList::~PythonList() +{ +} + +bool +PythonList::Reset(PyObject *py_obj) +{ + if (py_obj && PyList_Check(py_obj)) + return PythonObject::Reset(py_obj); + + PythonObject::Reset(nullptr); + return py_obj == nullptr; +} + +uint32_t +PythonList::GetSize() +{ + if (m_py_obj) + return PyList_GET_SIZE(m_py_obj); + return 0; +} + +PythonObject +PythonList::GetItemAtIndex(uint32_t index) +{ + if (m_py_obj) + return PythonObject(PyList_GetItem(m_py_obj, index)); + return PythonObject(); +} + +void +PythonList::SetItemAtIndex(uint32_t index, const PythonObject &object) +{ + if (m_py_obj && object) + 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.get()); +} + +//---------------------------------------------------------------------- +// PythonDictionary +//---------------------------------------------------------------------- + +PythonDictionary::PythonDictionary(bool create_empty) + : PythonObject(create_empty ? PyDict_New() : nullptr) +{ +} + +PythonDictionary::PythonDictionary(PyObject *py_obj) + : PythonObject(py_obj) +{ + Reset(py_obj); // Use "Reset()" to ensure that py_obj is a dictionary +} + +PythonDictionary::PythonDictionary(const PythonObject &object) + : PythonObject() +{ + Reset(object.get()); // Use "Reset()" to ensure that py_obj is a dictionary +} + +PythonDictionary::PythonDictionary(const lldb::ScriptInterpreterObjectSP &script_object_sp) + : PythonObject() +{ + if (script_object_sp) + Reset((PyObject *)script_object_sp->GetObject()); // Use "Reset()" to ensure that py_obj is a dictionary +} + +PythonDictionary::~PythonDictionary() +{ +} + +bool +PythonDictionary::Reset(PyObject *py_obj) +{ + if (py_obj && PyDict_Check(py_obj)) + return PythonObject::Reset(py_obj); + + PythonObject::Reset(nullptr); + return py_obj == nullptr; +} + +uint32_t +PythonDictionary::GetSize() +{ + if (m_py_obj) + return PyDict_Size(m_py_obj); + return 0; +} + +PythonObject +PythonDictionary::GetItemForKey(const char *key) const +{ + if (key && key[0]) + { + PythonString python_key(key); + return GetItemForKey(python_key); + } + return PythonObject(); +} + +PythonObject +PythonDictionary::GetItemForKey(const PythonString &key) const +{ + if (m_py_obj && key) + return PythonObject(PyDict_GetItem(m_py_obj, key.get())); + return PythonObject(); +} + +const char * +PythonDictionary::GetItemForKeyAsString(const PythonString &key, const char *fail_value) const +{ + if (m_py_obj && key) + { + PyObject *py_obj = PyDict_GetItem(m_py_obj, key.get()); + if (py_obj && PyString_Check(py_obj)) + return PyString_AsString(py_obj); + } + return fail_value; +} + +int64_t +PythonDictionary::GetItemForKeyAsInteger(const PythonString &key, int64_t fail_value) const +{ + if (m_py_obj && key) + { + PyObject *py_obj = PyDict_GetItem(m_py_obj, key.get()); + if (py_obj) + { + if (PyInt_Check(py_obj)) + return PyInt_AsLong(py_obj); + + if (PyLong_Check(py_obj)) + return PyLong_AsLong(py_obj); + } + } + return fail_value; +} + +PythonList +PythonDictionary::GetKeys() const +{ + if (m_py_obj) + return PythonList(PyDict_Keys(m_py_obj)); + return PythonList(true); +} + +PythonString +PythonDictionary::GetKeyAtPosition(uint32_t pos) const +{ + PyObject *key, *value; + Py_ssize_t pos_iter = 0; + + if (m_py_obj) + { + while (PyDict_Next(m_py_obj, &pos_iter, &key, &value)) + { + if (pos-- == 0) + return PythonString(key); + } + } + return PythonString(); +} + +PythonObject +PythonDictionary::GetValueAtPosition(uint32_t pos) const +{ + PyObject *key, *value; + Py_ssize_t pos_iter = 0; + + if (!m_py_obj) + return PythonObject(); + + while (PyDict_Next(m_py_obj, &pos_iter, &key, &value)) + { + if (pos-- == 0) + return PythonObject(value); + } + return PythonObject(); +} + +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.get(), value.get()); +} + +#endif Index: source/ScriptInterpreter/Python/ScriptInterpreterPython.cpp =================================================================== --- /dev/null +++ source/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -0,0 +1,2761 @@ +//===-- ScriptInterpreterPython.cpp -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// In order to guarantee correct working with Python, Python.h *MUST* be +// the *FIRST* header file included here. +#ifdef LLDB_DISABLE_PYTHON + +// Python is disabled in this build + +#else + +#include "lldb/lldb-python.h" +#include "lldb/ScriptInterpreter/Python/ScriptInterpreterPython.h" + +#include +#include + +#include + +#include "lldb/API/SBValue.h" +#include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Breakpoint/StoppointCallbackContext.h" +#include "lldb/Breakpoint/WatchpointOptions.h" +#include "lldb/Core/Communication.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Timer.h" +#include "lldb/Host/ConnectionFileDescriptor.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Host/Pipe.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/ScriptInterpreter/Python/PythonDataObjects.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadPlan.h" + +#if defined(_WIN32) +#include "lldb/Host/windows/ConnectionGenericFileWindows.h" +#endif + +using namespace lldb; +using namespace lldb_private; + +// these are the Pythonic implementations of the required callbacks +// these are scripting-language specific, which is why they belong here +// we still need to use function pointers to them instead of relying +// on linkage-time resolution because the SWIG stuff and this file +// get built at different times +// Defined in the SWIG source file +extern "C" void init_lldb(void); + +extern "C" bool LLDBSwigPythonBreakpointCallbackFunction(const char *python_function_name, const char *session_dictionary_name, + const lldb::StackFrameSP &sb_frame, const lldb::BreakpointLocationSP &sb_bp_loc); + +extern "C" bool LLDBSwigPythonWatchpointCallbackFunction(const char *python_function_name, const char *session_dictionary_name, + const lldb::StackFrameSP &sb_frame, const lldb::WatchpointSP &sb_wp); + +extern "C" bool LLDBSwigPythonCallTypeScript(const char *python_function_name, void *session_dictionary, + const lldb::ValueObjectSP &valobj_sp, void **pyfunct_wrapper, + const lldb::TypeSummaryOptionsSP &options_sp, std::string &retval); + +extern "C" void *LLDBSwigPythonCreateSyntheticProvider(const char *python_class_name, const char *session_dictionary_name, + const lldb::ValueObjectSP &valobj_sp); + +extern "C" void *LLDBSwigPythonCreateScriptedThreadPlan(const char *python_class_name, const char *session_dictionary_name, + const lldb::ThreadPlanSP &thread_plan_sp); + +extern "C" bool LLDBSWIGPythonCallThreadPlan(void *implementor, const char *method_name, Event *event_sp, bool &got_error); + +extern "C" uint32_t LLDBSwigPython_CalculateNumChildren(void *implementor); + +extern "C" void *LLDBSwigPython_GetChildAtIndex(void *implementor, uint32_t idx); + +extern "C" int LLDBSwigPython_GetIndexOfChildWithName(void *implementor, const char *child_name); + +extern "C" void *LLDBSWIGPython_CastPyObjectToSBValue(void *data); + +extern lldb::ValueObjectSP LLDBSWIGPython_GetValueObjectSPFromSBValue(void *data); + +extern "C" bool LLDBSwigPython_UpdateSynthProviderInstance(void *implementor); + +extern "C" bool LLDBSwigPython_MightHaveChildrenSynthProviderInstance(void *implementor); + +extern "C" void *LLDBSwigPython_GetValueSynthProviderInstance(void *implementor); + +extern "C" bool LLDBSwigPythonCallCommand(const char *python_function_name, const char *session_dictionary_name, lldb::DebuggerSP &debugger, + const char *args, lldb_private::CommandReturnObject &cmd_retobj, + lldb::ExecutionContextRefSP exe_ctx_ref_sp); + +extern "C" bool LLDBSwigPythonCallModuleInit(const char *python_module_name, const char *session_dictionary_name, + lldb::DebuggerSP &debugger); + +extern "C" void *LLDBSWIGPythonCreateOSPlugin(const char *python_class_name, const char *session_dictionary_name, + const lldb::ProcessSP &process_sp); + +extern "C" bool LLDBSWIGPythonRunScriptKeywordProcess(const char *python_function_name, const char *session_dictionary_name, + lldb::ProcessSP &process, std::string &output); + +extern "C" bool LLDBSWIGPythonRunScriptKeywordThread(const char *python_function_name, const char *session_dictionary_name, + lldb::ThreadSP &thread, std::string &output); + +extern "C" bool LLDBSWIGPythonRunScriptKeywordTarget(const char *python_function_name, const char *session_dictionary_name, + lldb::TargetSP &target, std::string &output); + +extern "C" bool LLDBSWIGPythonRunScriptKeywordFrame(const char *python_function_name, const char *session_dictionary_name, + lldb::StackFrameSP &frame, std::string &output); + +extern "C" bool LLDBSWIGPythonRunScriptKeywordValue(const char *python_function_name, const char *session_dictionary_name, + lldb::ValueObjectSP &value, std::string &output); + +extern "C" void *LLDBSWIGPython_GetDynamicSetting(void *module, const char *setting, const lldb::TargetSP &target_sp); + +static std::string ReadPythonBacktrace(PyObject *py_backtrace); + +ScriptInterpreterPython::Locker::Locker(ScriptInterpreterPython *py_interpreter, uint16_t on_entry, uint16_t on_leave, FILE *in, FILE *out, + FILE *err) + : ScriptInterpreterLocker() + , m_teardown_session((on_leave & TearDownSession) == TearDownSession) + , m_python_interpreter(py_interpreter) +{ + DoAcquireLock(); + if ((on_entry & InitSession) == InitSession) + { + if (DoInitSession(on_entry, in, out, err) == false) + { + // Don't teardown the session if we didn't init it. + m_teardown_session = false; + } + } +} + +bool +ScriptInterpreterPython::Locker::DoAcquireLock() +{ + Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT | LIBLLDB_LOG_VERBOSE)); + m_GILState = PyGILState_Ensure(); + if (log) + log->Printf("Ensured PyGILState. Previous state = %slocked\n", m_GILState == PyGILState_UNLOCKED ? "un" : ""); + + // we need to save the thread state when we first start the command + // because we might decide to interrupt it while some action is taking + // place outside of Python (e.g. printing to screen, waiting for the network, ...) + // in that case, _PyThreadState_Current will be NULL - and we would be unable + // to set the asynchronous exception - not a desirable situation + m_python_interpreter->SetThreadState (_PyThreadState_Current); + m_python_interpreter->IncrementLockCount(); + return true; +} + +bool +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 (on_entry_flags, in, out, err); +} + +bool +ScriptInterpreterPython::Locker::DoFreeLock() +{ + Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT | LIBLLDB_LOG_VERBOSE)); + if (log) + log->Printf("Releasing PyGILState. Returning to state = %slocked\n", m_GILState == PyGILState_UNLOCKED ? "un" : ""); + PyGILState_Release(m_GILState); + m_python_interpreter->DecrementLockCount(); + return true; +} + +bool +ScriptInterpreterPython::Locker::DoTearDownSession() +{ + if (!m_python_interpreter) + return false; + m_python_interpreter->LeaveSession (); + return true; +} + +ScriptInterpreterPython::Locker::~Locker() +{ + if (m_teardown_session) + DoTearDownSession(); + DoFreeLock(); +} + +ScriptInterpreterPython::ScriptInterpreterPython(CommandInterpreter &interpreter) + : ScriptInterpreter(interpreter, eScriptLanguagePython) + , 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_lock_count(0) + , m_command_thread_state(nullptr) +{ + + ScriptInterpreterPython::InitializePrivate (); + + m_dictionary_name.append("_dict"); + StreamString run_string; + run_string.Printf ("%s = dict()", m_dictionary_name.c_str()); + + Locker locker(this, ScriptInterpreterPython::Locker::AcquireLock, ScriptInterpreterPython::Locker::FreeAcquiredLock); + PyRun_SimpleString (run_string.GetData()); + + run_string.Clear(); + + // Importing 'lldb' module calls SBDebugger::Initialize, which calls Debugger::Initialize, which increments a + // global debugger ref-count; therefore we need to check the ref-count before and after importing lldb, and if the + // ref-count increased we need to call Debugger::Terminate here to decrement the ref-count so that when the final + // call to Debugger::Terminate is made, the ref-count has the correct value. + // + // Bonus question: Why doesn't the ref-count always increase? Because sometimes lldb has already been imported, in + // which case the code inside it, including the call to SBDebugger::Initialize(), does not get executed. + + int old_count = Debugger::TestDebuggerRefCount(); + + run_string.Printf ("run_one_line (%s, 'import copy, keyword, os, re, sys, uuid, lldb')", m_dictionary_name.c_str()); + PyRun_SimpleString (run_string.GetData()); + + // WARNING: temporary code that loads Cocoa formatters - this should be done on a per-platform basis rather than loading the whole set + // and letting the individual formatter classes exploit APIs to check whether they can/cannot do their task + 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()); +} + +ScriptInterpreterPython::~ScriptInterpreterPython () +{ +} + +void +ScriptInterpreterPython::IOHandlerActivated (IOHandler &io_handler) +{ + const char *instructions = nullptr; + + switch (m_active_io_handler) + { + 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 (instructions) + { + StreamFileSP output_sp(io_handler.GetOutputStreamFile()); + if (output_sp) + { + output_sp->PutCString(instructions); + output_sp->Flush(); + } + } +} + +void +ScriptInterpreterPython::IOHandlerInputComplete (IOHandler &io_handler, std::string &data) +{ + io_handler.SetIsDone(true); + bool batch_mode = m_interpreter.GetBatchCommandMode(); + + switch (m_active_io_handler) + { + case eIOHandlerNone: + break; + case eIOHandlerBreakpoint: + { + std::vector *bp_options_vec = (std::vector *)io_handler.GetUserData(); + for (auto bp_options : *bp_options_vec) + { + if (!bp_options) + continue; + + std::unique_ptr 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).Success()) + { + 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 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; + } +} + +void +ScriptInterpreterPython::ResetOutputFileHandle (FILE *fh) +{ +} + +void +ScriptInterpreterPython::SaveTerminalState (int fd) +{ + // Python mucks with the terminal state of STDIN. If we can possibly avoid + // this by setting the file handles up correctly prior to entering the + // interpreter we should. For now we save and restore the terminal state + // on the input file handle. + m_terminal_state.Save (fd, false); +} + +void +ScriptInterpreterPython::RestoreTerminalState () +{ + // Python mucks with the terminal state of STDIN. If we can possibly avoid + // this by setting the file handles up correctly prior to entering the + // interpreter we should. For now we save and restore the terminal state + // on the input file handle. + m_terminal_state.Restore(); +} + +void +ScriptInterpreterPython::LeaveSession () +{ + Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT)); + if (log) + log->PutCString("ScriptInterpreterPython::LeaveSession()"); + + // checking that we have a valid thread state - since we use our own threading and locking + // in some (rare) cases during cleanup Python may end up believing we have no thread state + // and PyImport_AddModule will crash if that is the case - since that seems to only happen + // when destroying the SBDebugger, we can make do without clearing up stdout and stderr + + // rdar://problem/11292882 + // When the current thread state is NULL, PyThreadState_Get() issues a fatal error. + if (PyThreadState_GetDict()) + { + PythonDictionary &sys_module_dict = GetSysModuleDictionary (); + if (sys_module_dict) + { + 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 (); + } + } + } + + m_session_is_active = false; +} + +bool +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. + Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT)); + if (m_session_is_active) + { + if (log) + 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(on_entry_flags=0x%" PRIx16 ")", on_entry_flags); + + m_session_is_active = true; + + StreamString run_string; + + 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()); + run_string.PutCString ("; lldb.target = lldb.debugger.GetSelectedTarget()"); + run_string.PutCString ("; lldb.process = lldb.target.GetProcess()"); + run_string.PutCString ("; lldb.thread = lldb.process.GetSelectedThread ()"); + run_string.PutCString ("; lldb.frame = lldb.thread.GetSelectedFrame ()"); + run_string.PutCString ("')"); + } + 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("; lldb.debugger = lldb.SBDebugger.FindDebuggerWithID (%" PRIu64 ")", + GetCommandInterpreter().GetDebugger().GetID()); + run_string.PutCString ("')"); + } + + PyRun_SimpleString (run_string.GetData()); + run_string.Clear(); + + PythonDictionary &sys_module_dict = GetSysModuleDictionary (); + if (sys_module_dict) + { + lldb::StreamFileSP in_sp; + lldb::StreamFileSP out_sp; + lldb::StreamFileSP err_sp; + if (in == nullptr || out == nullptr || err == nullptr) + m_interpreter.GetDebugger().AdoptTopIOHandlerFilesIfInvalid (in_sp, out_sp, err_sp); + + m_saved_stdin.Reset(); + + if ((on_entry_flags & Locker::NoSTDIN) == 0) + { + // STDIN is enabled + if (in == nullptr && in_sp) + in = in_sp->GetFile().GetStream(); + if (in) + { + m_saved_stdin.Reset(sys_module_dict.GetItemForKey("stdin")); + // This call can deadlock your process if the file is locked + PyObject *new_file = PyFile_FromFile (in, (char *) "", (char *) "r", nullptr); + sys_module_dict.SetItemForKey ("stdin", new_file); + Py_DECREF (new_file); + } + } + + if (out == nullptr && 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", nullptr); + sys_module_dict.SetItemForKey ("stdout", new_file); + Py_DECREF (new_file); + } + else + m_saved_stdout.Reset(); + + if (err == nullptr && 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", nullptr); + sys_module_dict.SetItemForKey ("stderr", new_file); + Py_DECREF (new_file); + } + else + m_saved_stderr.Reset(); + } + + if (PyErr_Occurred()) + PyErr_Clear (); + + return true; +} + +PythonObject & +ScriptInterpreterPython::GetMainModule () +{ + if (!m_main_module) + m_main_module.Reset(PyImport_AddModule ("__main__")); + return m_main_module; +} + +PythonDictionary & +ScriptInterpreterPython::GetSessionDictionary () +{ + if (!m_session_dict) + { + PythonObject &main_module = GetMainModule (); + if (main_module) + { + PythonDictionary main_dict(PyModule_GetDict (main_module.get())); + if (main_dict) + { + m_session_dict = main_dict.GetItemForKey(m_dictionary_name.c_str()); + } + } + } + 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 +GenerateUniqueName(const char *base_name_wanted, uint32_t &functions_counter, const void *name_token = nullptr) +{ + StreamString sstr; + + if (!base_name_wanted) + return std::string(); + + if (!name_token) + sstr.Printf ("%s_%d", base_name_wanted, functions_counter++); + else + sstr.Printf ("%s_%p", base_name_wanted, name_token); + + return sstr.GetString(); +} + +bool +ScriptInterpreterPython::GetEmbeddedInterpreterModuleObjects () +{ + if (!m_run_one_line_function) + { + PyObject *module = PyImport_AddModule ("lldb.embedded_interpreter"); + if (module != nullptr) + { + PythonDictionary module_dict (PyModule_GetDict (module)); + if (module_dict) + { + m_run_one_line_function = module_dict.GetItemForKey("run_one_line"); + m_run_one_line_str_global = module_dict.GetItemForKey("g_run_one_line_str"); + } + } + } + return (bool)m_run_one_line_function; +} + +static void +ReadThreadBytesReceived(void *baton, const void *src, size_t src_len) +{ + if (src && src_len) + { + Stream *strm = (Stream *)baton; + strm->Write(src, src_len); + strm->Flush(); + } +} + +bool +ScriptInterpreterPython::ExecuteOneLine (const char *command, CommandReturnObject *result, const ExecuteScriptOptions &options) +{ + if (!m_valid_session) + return false; + + if (command && command[0]) + { + // We want to call run_one_line, passing in the dictionary and the command string. We cannot do this through + // PyRun_SimpleString here because the command string may contain escaped characters, and putting it inside + // another string to pass to PyRun_SimpleString messes up the escaping. So we use the following more complicated + // method to pass the command string directly down to Python. + Debugger &debugger = m_interpreter.GetDebugger(); + + StreamFileSP input_file_sp; + StreamFileSP output_file_sp; + StreamFileSP error_file_sp; + Communication output_comm ("lldb.ScriptInterpreterPython.ExecuteOneLine.comm"); + bool join_read_thread = false; + if (options.GetEnableIO()) + { + if (result) + { + input_file_sp = debugger.GetInputFile(); + // Set output to a temporary file so we can forward the results on to the result object + + Pipe pipe; + Error pipe_result = pipe.CreateNew(false); + if (pipe_result.Success()) + { +#if defined(_WIN32) + lldb::file_t read_file = pipe.GetReadNativeHandle(); + pipe.ReleaseReadFileDescriptor(); + std::unique_ptr conn_ap(new ConnectionGenericFile(read_file, true)); +#else + std::unique_ptr conn_ap(new ConnectionFileDescriptor(pipe.ReleaseReadFileDescriptor(), true)); +#endif + if (conn_ap->IsConnected()) + { + output_comm.SetConnection(conn_ap.release()); + output_comm.SetReadThreadBytesReceivedCallback(ReadThreadBytesReceived, &result->GetOutputStream()); + output_comm.StartReadThread(); + join_read_thread = true; + FILE *outfile_handle = fdopen (pipe.ReleaseWriteFileDescriptor(), "w"); + output_file_sp.reset(new StreamFile(outfile_handle, true)); + error_file_sp = output_file_sp; + if (outfile_handle) + ::setbuf (outfile_handle, nullptr); + + result->SetImmediateOutputFile(debugger.GetOutputFile()->GetFile().GetStream()); + result->SetImmediateErrorFile(debugger.GetErrorFile()->GetFile().GetStream()); + } + } + } + if (!input_file_sp || !output_file_sp || !error_file_sp) + debugger.AdoptTopIOHandlerFilesIfInvalid(input_file_sp, output_file_sp, error_file_sp); + } + else + { + input_file_sp.reset (new StreamFile ()); + input_file_sp->GetFile().Open("/dev/null", File::eOpenOptionRead); + output_file_sp.reset (new StreamFile ()); + output_file_sp->GetFile().Open("/dev/null", File::eOpenOptionWrite); + error_file_sp = output_file_sp; + } + + 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) | + ((result && result->GetInteractive()) ? 0: Locker::NoSTDIN), + 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) + { + PythonObject return_value(PyObject_CallObject (pfunc, pargs.get())); + if (return_value) + success = true; + else if (options.GetMaskoutErrors() && PyErr_Occurred ()) + { + PyErr_Print(); + PyErr_Clear(); + } + } + } + } + } + + // Flush our output and error file handles + ::fflush (out_file); + if (out_file != err_file) + ::fflush (err_file); + + if (join_read_thread) + { + // 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; + + // The one-liner failed. Append the error message. + if (result) + result->AppendErrorWithFormat ("python failed attempting to evaluate '%s'\n", command); + return false; + } + + if (result) + result->AppendError ("empty command passed to python\n"); + return false; +} + +class IOHandlerPythonInterpreter : public IOHandler +{ +public: + IOHandlerPythonInterpreter(Debugger &debugger, ScriptInterpreterPython *python) + : IOHandler(debugger, IOHandler::Type::PythonInterpreter) + , m_python(python) + { + } + + virtual ~IOHandlerPythonInterpreter() {} + + virtual ConstString + GetControlSequence (char ch) + { + if (ch == 'd') + return ConstString("quit()\n"); + return ConstString(); + } + + virtual void + Run () + { + if (m_python) + { + int stdin_fd = GetInputFD(); + if (stdin_fd >= 0) + { + Terminal terminal(stdin_fd); + TerminalState terminal_state; + const bool is_a_tty = terminal.IsATerminal(); + + if (is_a_tty) + { + terminal_state.Save (stdin_fd, false); + terminal.SetCanonical(false); + terminal.SetEcho(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(); + } + } + SetIsDone(true); + } + + virtual void + Hide () + { + } + + virtual void + Refresh () + { + } + + virtual void + Cancel () + { + } + + virtual bool + Interrupt () + { + return m_python->Interrupt(); + } + + virtual void + GotEOF() + { + } + +protected: + ScriptInterpreterPython *m_python; +}; + +void +ScriptInterpreterPython::ExecuteInterpreterLoop () +{ + Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__); + + Debugger &debugger = GetCommandInterpreter().GetDebugger(); + + // At the moment, the only time the debugger does not have an input file handle is when this is called + // directly from Python, in which case it is both dangerous and unnecessary (not to mention confusing) to + // try to embed a running interpreter loop inside the already running Python interpreter loop, so we won't + // do it. + + if (!debugger.GetInputFile()->GetFile().IsValid()) + return; + + IOHandlerSP io_handler_sp (new IOHandlerPythonInterpreter (debugger, this)); + if (io_handler_sp) + { + debugger.PushIOHandler(io_handler_sp); + } +} + +bool +ScriptInterpreterPython::Interrupt() +{ + Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT)); + + if (IsExecutingPython()) + { + PyThreadState* state = _PyThreadState_Current; + if (!state) + state = GetThreadState(); + if (state) + { + long tid = state->thread_id; + _PyThreadState_Current = state; + int num_threads = PyThreadState_SetAsyncExc(tid, PyExc_KeyboardInterrupt); + if (log) + log->Printf("ScriptInterpreterPython::Interrupt() sending PyExc_KeyboardInterrupt (tid = %li, num_threads = %i)...", tid, + num_threads); + return true; + } + } + if (log) + log->Printf("ScriptInterpreterPython::Interrupt() python code not running, can't interrupt"); + return false; +} +bool +ScriptInterpreterPython::ExecuteOneLineWithReturn(const char *in_string, ScriptInterpreter::ScriptReturnType return_type, void *ret_value, + const ExecuteScriptOptions &options) +{ + + Locker locker(this, ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | + (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0) | Locker::NoSTDIN, + ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession); + + PyObject *py_return = nullptr; + PythonObject &main_module = GetMainModule (); + PythonDictionary globals (PyModule_GetDict(main_module.get())); + PyObject *py_error = nullptr; + bool ret_success = false; + int success; + + PythonDictionary locals = GetSessionDictionary (); + + if (!locals) + { + locals = PyObject_GetAttrString (globals.get(), m_dictionary_name.c_str()); + } + + if (!locals) + locals = globals; + + py_error = PyErr_Occurred(); + if (py_error != nullptr) + PyErr_Clear(); + + if (in_string != nullptr) + { + { // scope for PythonInputReaderManager + //PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL); + py_return = PyRun_String (in_string, Py_eval_input, globals.get(), locals.get()); + if (py_return == nullptr) + { + py_error = PyErr_Occurred (); + if (py_error != nullptr) + PyErr_Clear (); + + py_return = PyRun_String (in_string, Py_single_input, globals.get(), locals.get()); + } + } + + if (py_return != nullptr) + { + switch (return_type) + { + case eScriptReturnTypeCharPtr: // "char *" + { + const char format[3] = "s#"; + success = PyArg_Parse (py_return, format, (char **) ret_value); + break; + } + case eScriptReturnTypeCharStrOrNone: // char* or NULL if py_return == Py_None + { + const char format[3] = "z"; + success = PyArg_Parse (py_return, format, (char **) ret_value); + break; + } + case eScriptReturnTypeBool: + { + const char format[2] = "b"; + success = PyArg_Parse (py_return, format, (bool *) ret_value); + break; + } + case eScriptReturnTypeShortInt: + { + const char format[2] = "h"; + success = PyArg_Parse (py_return, format, (short *) ret_value); + break; + } + case eScriptReturnTypeShortIntUnsigned: + { + const char format[2] = "H"; + success = PyArg_Parse (py_return, format, (unsigned short *) ret_value); + break; + } + case eScriptReturnTypeInt: + { + const char format[2] = "i"; + success = PyArg_Parse (py_return, format, (int *) ret_value); + break; + } + case eScriptReturnTypeIntUnsigned: + { + const char format[2] = "I"; + success = PyArg_Parse (py_return, format, (unsigned int *) ret_value); + break; + } + case eScriptReturnTypeLongInt: + { + const char format[2] = "l"; + success = PyArg_Parse (py_return, format, (long *) ret_value); + break; + } + case eScriptReturnTypeLongIntUnsigned: + { + const char format[2] = "k"; + success = PyArg_Parse (py_return, format, (unsigned long *) ret_value); + break; + } + case eScriptReturnTypeLongLong: + { + const char format[2] = "L"; + success = PyArg_Parse (py_return, format, (long long *) ret_value); + break; + } + case eScriptReturnTypeLongLongUnsigned: + { + const char format[2] = "K"; + success = PyArg_Parse (py_return, format, (unsigned long long *) ret_value); + break; + } + case eScriptReturnTypeFloat: + { + const char format[2] = "f"; + success = PyArg_Parse (py_return, format, (float *) ret_value); + break; + } + case eScriptReturnTypeDouble: + { + const char format[2] = "d"; + success = PyArg_Parse (py_return, format, (double *) ret_value); + break; + } + case eScriptReturnTypeChar: + { + const char format[2] = "c"; + success = PyArg_Parse (py_return, format, (char *) ret_value); + break; + } + case eScriptReturnTypeOpaqueObject: + { + success = true; + Py_XINCREF(py_return); + *((PyObject**)ret_value) = py_return; + break; + } + } + Py_XDECREF (py_return); + if (success) + ret_success = true; + else + ret_success = false; + } + } + + py_error = PyErr_Occurred(); + if (py_error != nullptr) + { + ret_success = false; + if (options.GetMaskoutErrors()) + { + if (PyErr_GivenExceptionMatches (py_error, PyExc_SyntaxError)) + PyErr_Print (); + PyErr_Clear(); + } + } + + return ret_success; +} + +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) | Locker::NoSTDIN, + ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession); + + PythonObject return_value; + PythonObject &main_module = GetMainModule (); + PythonDictionary globals (PyModule_GetDict(main_module.get())); + PyObject *py_error = nullptr; + + PythonDictionary locals = GetSessionDictionary (); + + if (!locals) + { + locals = PyObject_GetAttrString (globals.get(), m_dictionary_name.c_str()); + } + + if (!locals) + { + locals = globals; + } + + py_error = PyErr_Occurred(); + if (py_error != nullptr) + PyErr_Clear(); + + if (in_string != nullptr) + { + struct _node *compiled_node = PyParser_SimpleParseString (in_string, Py_file_input); + if (compiled_node) + { + PyCodeObject *compiled_code = PyNode_Compile (compiled_node, "temp.py"); + if (compiled_code) + { + return_value.Reset(PyEval_EvalCode (compiled_code, globals.get(), locals.get())); + } + } + } + + py_error = PyErr_Occurred (); + if (py_error != nullptr) + { +// puts(in_string); +// _PyObject_Dump (py_error); +// PyErr_Print(); +// success = false; + + PyObject *type = nullptr; + PyObject *value = nullptr; + PyObject *traceback = nullptr; + PyErr_Fetch (&type,&value,&traceback); + + // get the backtrace + std::string bt = ReadPythonBacktrace(traceback); + + 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()) + { + PyErr_Clear(); + } + } + + return error; +} + +void +ScriptInterpreterPython::CollectDataForBreakpointCommandCallback (std::vector &bp_options_vec, + CommandReturnObject &result) +{ + m_active_io_handler = eIOHandlerBreakpoint; + m_interpreter.GetPythonCommandsFromIOHandler (" ", *this, true, &bp_options_vec); +} + +void +ScriptInterpreterPython::CollectDataForWatchpointCommandCallback(WatchpointOptions *wp_options, CommandReturnObject &result) +{ + m_active_io_handler = eIOHandlerWatchpoint; + m_interpreter.GetPythonCommandsFromIOHandler (" ", *this, true, wp_options); +} + +void +ScriptInterpreterPython::SetBreakpointCommandCallbackFunction(BreakpointOptions *bp_options, const char *function_name) +{ + // For now just cons up a oneliner that calls the provided function. + std::string oneliner("return "); + oneliner += function_name; + oneliner += "(frame, bp_loc, internal_dict)"; + m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback(bp_options, oneliner.c_str()); +} + +// Set a Python one-liner as the callback for the breakpoint. +Error +ScriptInterpreterPython::SetBreakpointCommandCallback(BreakpointOptions *bp_options, const char *command_body_text) +{ + std::unique_ptr data_ap(new BreakpointOptions::CommandData()); + + // Split the command_body_text into lines, and pass that to GenerateBreakpointCommandCallbackData. That will + // wrap the body in an auto-generated function, and return the function name in script_source. That is what + // the callback will actually invoke. + + data_ap->user_source.SplitIntoLines(command_body_text); + Error error = GenerateBreakpointCommandCallbackData (data_ap->user_source, data_ap->script_source); + if (error.Success()) + { + BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); + bp_options->SetCallback (ScriptInterpreterPython::BreakpointCallbackFunction, baton_sp); + return error; + } + else + return error; +} + +// Set a Python one-liner as the callback for the watchpoint. +void +ScriptInterpreterPython::SetWatchpointCommandCallback(WatchpointOptions *wp_options, const char *oneliner) +{ + std::unique_ptr data_ap(new WatchpointOptions::CommandData()); + + // It's necessary to set both user_source and script_source to the oneliner. + // The former is used to generate callback description (as in watchpoint command list) + // while the latter is used for Python to interpret during the actual callback. + + data_ap->user_source.AppendString (oneliner); + data_ap->script_source.assign (oneliner); + + 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); + } + + return; +} + +Error +ScriptInterpreterPython::ExportFunctionDefinitionToInterpreter (StringList &function_def) +{ + // Convert StringList to one long, newline delimited, const char *. + std::string function_def_string(function_def.CopyList()); + + Error error = ExecuteMultipleLines (function_def_string.c_str(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false)); + return error; +} + +Error +ScriptInterpreterPython::GenerateFunction(const char *signature, const StringList &input) +{ + Error error; + int num_lines = input.GetSize (); + if (num_lines == 0) + { + error.SetErrorString ("No input data."); + return error; + } + + if (!signature || *signature == 0) + { + error.SetErrorString("No output function name."); + return error; + } + + StreamString sstr; + StringList auto_generated_function; + auto_generated_function.AppendString (signature); + auto_generated_function.AppendString (" global_dict = globals()"); // Grab the global dictionary + auto_generated_function.AppendString (" new_keys = internal_dict.keys()"); // Make a list of keys in the session dict + auto_generated_function.AppendString (" old_keys = global_dict.keys()"); // Save list of keys in global dict + auto_generated_function.AppendString (" global_dict.update (internal_dict)"); // Add the session dictionary to the + // global dictionary. + + // Wrap everything up inside the function, increasing the indentation. + + auto_generated_function.AppendString(" if True:"); + for (int i = 0; i < num_lines; ++i) + { + sstr.Clear (); + sstr.Printf (" %s", input.GetStringAtIndex (i)); + auto_generated_function.AppendString (sstr.GetData()); + } + auto_generated_function.AppendString (" for key in new_keys:"); // Iterate over all the keys from session dict + auto_generated_function.AppendString (" internal_dict[key] = global_dict[key]"); // Update session dict values + auto_generated_function.AppendString (" if key not in old_keys:"); // If key was not originally in global dict + auto_generated_function.AppendString (" del global_dict[key]"); // ...then remove key/value from global dict + + // Verify that the results are valid Python. + + error = ExportFunctionDefinitionToInterpreter (auto_generated_function); + + return error; +} + +bool +ScriptInterpreterPython::GenerateTypeScriptFunction (StringList &user_input, std::string& output, const void* name_token) +{ + static uint32_t num_created_functions = 0; + user_input.RemoveBlankLines (); + StreamString sstr; + + // Check to see if we have any data; if not, just return. + if (user_input.GetSize() == 0) + return false; + + // Take what the user wrote, wrap it all up inside one big auto-generated Python function, passing in the + // ValueObject as parameter to the function. + + std::string auto_generated_function_name(GenerateUniqueName("lldb_autogen_python_type_print_func", num_created_functions, name_token)); + sstr.Printf ("def %s (valobj, internal_dict):", auto_generated_function_name.c_str()); + + if (!GenerateFunction(sstr.GetData(), user_input).Success()) + return false; + + // Store the name of the auto-generated function to be called. + output.assign(auto_generated_function_name); + return true; +} + +bool +ScriptInterpreterPython::GenerateScriptAliasFunction (StringList &user_input, std::string &output) +{ + static uint32_t num_created_functions = 0; + user_input.RemoveBlankLines (); + StreamString sstr; + + // Check to see if we have any data; if not, just return. + if (user_input.GetSize() == 0) + return false; + + std::string auto_generated_function_name(GenerateUniqueName("lldb_autogen_python_cmd_alias_func", num_created_functions)); + + sstr.Printf ("def %s (debugger, args, result, internal_dict):", auto_generated_function_name.c_str()); + + if (!GenerateFunction(sstr.GetData(),user_input).Success()) + return false; + + // Store the name of the auto-generated function to be called. + output.assign(auto_generated_function_name); + return true; +} + +bool +ScriptInterpreterPython::GenerateTypeSynthClass (StringList &user_input, std::string &output, const void* name_token) +{ + static uint32_t num_created_classes = 0; + user_input.RemoveBlankLines (); + int num_lines = user_input.GetSize (); + StreamString sstr; + + // Check to see if we have any data; if not, just return. + if (user_input.GetSize() == 0) + return false; + + // Wrap all user input into a Python class + + std::string auto_generated_class_name(GenerateUniqueName("lldb_autogen_python_type_synth_class",num_created_classes,name_token)); + + StringList auto_generated_class; + + // Create the function name & definition string. + + sstr.Printf ("class %s:", auto_generated_class_name.c_str()); + auto_generated_class.AppendString (sstr.GetData()); + + // Wrap everything up inside the class, increasing the indentation. + // we don't need to play any fancy indentation tricks here because there is no + // surrounding code whose indentation we need to honor + for (int i = 0; i < num_lines; ++i) + { + sstr.Clear (); + sstr.Printf (" %s", user_input.GetStringAtIndex (i)); + auto_generated_class.AppendString (sstr.GetData()); + } + + // Verify that the results are valid Python. + // (even though the method is ExportFunctionDefinitionToInterpreter, a class will actually be exported) + // (TODO: rename that method to ExportDefinitionToInterpreter) + if (!ExportFunctionDefinitionToInterpreter (auto_generated_class).Success()) + return false; + + // Store the name of the auto-generated class + + output.assign(auto_generated_class_name); + return true; +} + +lldb::ScriptInterpreterObjectSP +ScriptInterpreterPython::OSPlugin_CreatePluginObject (const char *class_name, lldb::ProcessSP process_sp) +{ + if (class_name == nullptr || class_name[0] == '\0') + return lldb::ScriptInterpreterObjectSP(); + + if (!process_sp) + return lldb::ScriptInterpreterObjectSP(); + + void* ret_val; + + { + Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); + ret_val = LLDBSWIGPythonCreateOSPlugin(class_name, m_dictionary_name.c_str(), process_sp); + } + + return MakeScriptObject(ret_val); +} + +lldb::ScriptInterpreterObjectSP +ScriptInterpreterPython::OSPlugin_RegisterInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp) +{ + Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); + + static char callee_name[] = "get_register_info"; + + if (!os_plugin_object_sp) + return lldb::ScriptInterpreterObjectSP(); + + PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject(); + + if (implementor == nullptr || implementor == Py_None) + return lldb::ScriptInterpreterObjectSP(); + + PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); + + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + if (pmeth == nullptr || pmeth == Py_None) + { + Py_XDECREF(pmeth); + return lldb::ScriptInterpreterObjectSP(); + } + + if (PyCallable_Check(pmeth) == 0) + { + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + Py_XDECREF(pmeth); + return lldb::ScriptInterpreterObjectSP(); + } + + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + Py_XDECREF(pmeth); + + // right now we know this function exists and is callable.. + PyObject* py_return = PyObject_CallMethod(implementor, callee_name, nullptr); + + // if it fails, print the error but otherwise go on + if (PyErr_Occurred()) + { + PyErr_Print(); + PyErr_Clear(); + } + + return MakeScriptObject(py_return); +} + +lldb::ScriptInterpreterObjectSP +ScriptInterpreterPython::OSPlugin_ThreadsInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp) +{ + Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); + + static char callee_name[] = "get_thread_info"; + + if (!os_plugin_object_sp) + return lldb::ScriptInterpreterObjectSP(); + + PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject(); + + if (implementor == nullptr || implementor == Py_None) + return lldb::ScriptInterpreterObjectSP(); + + PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); + + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + if (pmeth == nullptr || pmeth == Py_None) + { + Py_XDECREF(pmeth); + return lldb::ScriptInterpreterObjectSP(); + } + + if (PyCallable_Check(pmeth) == 0) + { + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + Py_XDECREF(pmeth); + return lldb::ScriptInterpreterObjectSP(); + } + + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + Py_XDECREF(pmeth); + + // right now we know this function exists and is callable.. + PyObject* py_return = PyObject_CallMethod(implementor, callee_name, nullptr); + + // if it fails, print the error but otherwise go on + if (PyErr_Occurred()) + { + PyErr_Print(); + PyErr_Clear(); + } + + return MakeScriptObject(py_return); +} + +// GetPythonValueFormatString provides a system independent type safe way to +// convert a variable's type into a python value format. Python value formats +// are defined in terms of builtin C types and could change from system to +// as the underlying typedef for uint* types, size_t, off_t and other values +// change. + +template +const char * +GetPythonValueFormatString(T t) +{ + assert(!"Unhandled type passed to GetPythonValueFormatString(T), make a specialization of GetPythonValueFormatString() to support this " + "type."); + return nullptr; +} +template <> +const char * +GetPythonValueFormatString(char *) +{ + return "s"; +} +template <> +const char * +GetPythonValueFormatString(char) +{ + return "b"; +} +template <> +const char * +GetPythonValueFormatString(unsigned char) +{ + return "B"; +} +template <> +const char * +GetPythonValueFormatString(short) +{ + return "h"; +} +template <> +const char * +GetPythonValueFormatString(unsigned short) +{ + return "H"; +} +template <> +const char * +GetPythonValueFormatString(int) +{ + return "i"; +} +template <> +const char * +GetPythonValueFormatString(unsigned int) +{ + return "I"; +} +template <> +const char * +GetPythonValueFormatString(long) +{ + return "l"; +} +template <> +const char * +GetPythonValueFormatString(unsigned long) +{ + return "k"; +} +template <> +const char * +GetPythonValueFormatString(long long) +{ + return "L"; +} +template <> +const char * +GetPythonValueFormatString(unsigned long long) +{ + return "K"; +} +template <> +const char * +GetPythonValueFormatString(float t) +{ + return "f"; +} +template <> +const char * +GetPythonValueFormatString(double t) +{ + return "d"; +} + +lldb::ScriptInterpreterObjectSP +ScriptInterpreterPython::OSPlugin_RegisterContextData(lldb::ScriptInterpreterObjectSP os_plugin_object_sp, lldb::tid_t tid) +{ + Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); + + static char callee_name[] = "get_register_data"; + static char *param_format = const_cast(GetPythonValueFormatString(tid)); + + if (!os_plugin_object_sp) + return lldb::ScriptInterpreterObjectSP(); + + PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject(); + + if (implementor == nullptr || implementor == Py_None) + return lldb::ScriptInterpreterObjectSP(); + + PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); + + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + if (pmeth == nullptr || pmeth == Py_None) + { + Py_XDECREF(pmeth); + return lldb::ScriptInterpreterObjectSP(); + } + + if (PyCallable_Check(pmeth) == 0) + { + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + Py_XDECREF(pmeth); + return lldb::ScriptInterpreterObjectSP(); + } + + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + Py_XDECREF(pmeth); + + // right now we know this function exists and is callable.. + PyObject* py_return = PyObject_CallMethod(implementor, callee_name, param_format, tid); + + // if it fails, print the error but otherwise go on + if (PyErr_Occurred()) + { + PyErr_Print(); + PyErr_Clear(); + } + + return MakeScriptObject(py_return); +} + +lldb::ScriptInterpreterObjectSP +ScriptInterpreterPython::OSPlugin_CreateThread(lldb::ScriptInterpreterObjectSP os_plugin_object_sp, lldb::tid_t tid, lldb::addr_t context) +{ + Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); + + static char callee_name[] = "create_thread"; + std::string param_format; + param_format += GetPythonValueFormatString(tid); + param_format += GetPythonValueFormatString(context); + + if (!os_plugin_object_sp) + return lldb::ScriptInterpreterObjectSP(); + + PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject(); + + if (implementor == nullptr || implementor == Py_None) + return lldb::ScriptInterpreterObjectSP(); + + PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); + + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + if (pmeth == nullptr || pmeth == Py_None) + { + Py_XDECREF(pmeth); + return lldb::ScriptInterpreterObjectSP(); + } + + if (PyCallable_Check(pmeth) == 0) + { + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + Py_XDECREF(pmeth); + return lldb::ScriptInterpreterObjectSP(); + } + + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + Py_XDECREF(pmeth); + + // right now we know this function exists and is callable.. + PyObject* py_return = PyObject_CallMethod(implementor, callee_name, ¶m_format[0], tid, context); + + // if it fails, print the error but otherwise go on + if (PyErr_Occurred()) + { + PyErr_Print(); + PyErr_Clear(); + } + + return MakeScriptObject(py_return); +} + +lldb::ScriptInterpreterObjectSP +ScriptInterpreterPython::CreateScriptedThreadPlan(const char *class_name, lldb::ThreadPlanSP thread_plan_sp) +{ + if (class_name == nullptr || class_name[0] == '\0') + return lldb::ScriptInterpreterObjectSP(); + + if (!thread_plan_sp.get()) + return lldb::ScriptInterpreterObjectSP(); + + Debugger &debugger = thread_plan_sp->GetTarget().GetDebugger(); + ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter(); + ScriptInterpreterPython *python_interpreter = static_cast(script_interpreter); + + if (!script_interpreter) + return lldb::ScriptInterpreterObjectSP(); + + void* ret_val; + + { + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + + ret_val = LLDBSwigPythonCreateScriptedThreadPlan(class_name, python_interpreter->m_dictionary_name.c_str(), thread_plan_sp); + } + + return MakeScriptObject(ret_val); +} + +bool +ScriptInterpreterPython::ScriptedThreadPlanExplainsStop(lldb::ScriptInterpreterObjectSP implementor_sp, Event *event, bool &script_error) +{ + bool explains_stop = true; + if (implementor_sp) + { + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + explains_stop = LLDBSWIGPythonCallThreadPlan(implementor_sp->GetObject(), "explains_stop", event, script_error); + if (script_error) + return true; + } + return explains_stop; +} + +bool +ScriptInterpreterPython::ScriptedThreadPlanShouldStop(lldb::ScriptInterpreterObjectSP implementor_sp, Event *event, bool &script_error) +{ + bool should_stop = true; + if (implementor_sp) + { + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + should_stop = LLDBSWIGPythonCallThreadPlan(implementor_sp->GetObject(), "should_stop", event, script_error); + if (script_error) + return true; + } + return should_stop; +} + +lldb::StateType +ScriptInterpreterPython::ScriptedThreadPlanGetRunState(lldb::ScriptInterpreterObjectSP implementor_sp, bool &script_error) +{ + bool should_step = false; + if (implementor_sp) + { + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + should_step = LLDBSWIGPythonCallThreadPlan(implementor_sp->GetObject(), "should_step", NULL, script_error); + if (script_error) + should_step = true; + } + if (should_step) + return lldb::eStateStepping; + else + return lldb::eStateRunning; +} + +lldb::ScriptInterpreterObjectSP +ScriptInterpreterPython::LoadPluginModule(const FileSpec &file_spec, lldb_private::Error &error) +{ + if (!file_spec.Exists()) + { + error.SetErrorString("no such file"); + return lldb::ScriptInterpreterObjectSP(); + } + + ScriptInterpreterObjectSP module_sp; + + if (LoadScriptingModule(file_spec.GetPath().c_str(),true,true,error,&module_sp)) + return module_sp; + + return lldb::ScriptInterpreterObjectSP(); +} + +lldb::ScriptInterpreterObjectSP +ScriptInterpreterPython::GetDynamicSettings(lldb::ScriptInterpreterObjectSP plugin_module_sp, Target *target, const char *setting_name, + lldb_private::Error& error) +{ + if (!plugin_module_sp || !target || !setting_name || !setting_name[0]) + return lldb::ScriptInterpreterObjectSP(); + + PyObject *reply_pyobj = nullptr; + + { + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + TargetSP target_sp(target->shared_from_this()); + reply_pyobj = (PyObject *)LLDBSWIGPython_GetDynamicSetting(plugin_module_sp->GetObject(), setting_name, target_sp); + } + + return MakeScriptObject(reply_pyobj); +} + +lldb::ScriptInterpreterObjectSP +ScriptInterpreterPython::CreateSyntheticScriptedProvider(const char *class_name, lldb::ValueObjectSP valobj) +{ + if (class_name == nullptr || class_name[0] == '\0') + return lldb::ScriptInterpreterObjectSP(); + + if (!valobj.get()) + return lldb::ScriptInterpreterObjectSP(); + + ExecutionContext exe_ctx (valobj->GetExecutionContextRef()); + Target *target = exe_ctx.GetTargetPtr(); + + if (!target) + return lldb::ScriptInterpreterObjectSP(); + + Debugger &debugger = target->GetDebugger(); + ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter(); + ScriptInterpreterPython *python_interpreter = (ScriptInterpreterPython *) script_interpreter; + + if (!script_interpreter) + return lldb::ScriptInterpreterObjectSP(); + + void* ret_val; + + { + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + ret_val = LLDBSwigPythonCreateSyntheticProvider(class_name, python_interpreter->m_dictionary_name.c_str(), valobj); + } + + return MakeScriptObject(ret_val); +} + +bool +ScriptInterpreterPython::GenerateTypeScriptFunction (const char* oneliner, std::string& output, const void* name_token) +{ + StringList input; + input.SplitIntoLines(oneliner, strlen(oneliner)); + return GenerateTypeScriptFunction(input, output, name_token); +} + +bool +ScriptInterpreterPython::GenerateTypeSynthClass (const char* oneliner, std::string& output, const void* name_token) +{ + StringList input; + input.SplitIntoLines(oneliner, strlen(oneliner)); + return GenerateTypeSynthClass(input, output, name_token); +} + +Error +ScriptInterpreterPython::GenerateBreakpointCommandCallbackData (StringList &user_input, std::string& output) +{ + static uint32_t num_created_functions = 0; + user_input.RemoveBlankLines (); + StreamString sstr; + Error error; + if (user_input.GetSize() == 0) + { + error.SetErrorString("No input data."); + return error; + } + + std::string auto_generated_function_name(GenerateUniqueName("lldb_autogen_python_bp_callback_func_",num_created_functions)); + sstr.Printf ("def %s (frame, bp_loc, internal_dict):", auto_generated_function_name.c_str()); + + error = GenerateFunction(sstr.GetData(), user_input); + if (!error.Success()) + return error; + + // Store the name of the auto-generated function to be called. + output.assign(auto_generated_function_name); + return error; +} + +bool +ScriptInterpreterPython::GenerateWatchpointCommandCallbackData (StringList &user_input, std::string& output) +{ + static uint32_t num_created_functions = 0; + user_input.RemoveBlankLines (); + StreamString sstr; + + if (user_input.GetSize() == 0) + return false; + + std::string auto_generated_function_name(GenerateUniqueName("lldb_autogen_python_wp_callback_func_",num_created_functions)); + sstr.Printf ("def %s (frame, wp, internal_dict):", auto_generated_function_name.c_str()); + + if (!GenerateFunction(sstr.GetData(), user_input).Success()) + return false; + + // Store the name of the auto-generated function to be called. + output.assign(auto_generated_function_name); + return true; +} + +bool +ScriptInterpreterPython::GetScriptedSummary(const char *python_function_name, lldb::ValueObjectSP valobj, + lldb::ScriptInterpreterObjectSP &callee_wrapper_sp, const TypeSummaryOptions &options, + std::string& retval) +{ + + Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__); + + if (!valobj.get()) + { + retval.assign(""); + return false; + } + + void* old_callee = (callee_wrapper_sp ? callee_wrapper_sp->GetObject() : nullptr); + void* new_callee = old_callee; + + bool ret_val; + if (python_function_name && *python_function_name) + { + { + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + { + TypeSummaryOptionsSP options_sp(new TypeSummaryOptions(options)); + + Timer scoped_timer("LLDBSwigPythonCallTypeScript", "LLDBSwigPythonCallTypeScript"); + ret_val = LLDBSwigPythonCallTypeScript(python_function_name, GetSessionDictionary().get(), valobj, &new_callee, options_sp, + retval); + } + } + } + else + { + retval.assign(""); + return false; + } + + if (new_callee && old_callee != new_callee) + callee_wrapper_sp = MakeScriptObject(new_callee); + + return ret_val; +} + +void +ScriptInterpreterPython::Clear () +{ + // Release any global variables that might have strong references to + // LLDB objects when clearing the python script interpreter. + Locker locker(this, ScriptInterpreterPython::Locker::AcquireLock, ScriptInterpreterPython::Locker::FreeAcquiredLock); + + // This may be called as part of Py_Finalize. In that case the modules are destroyed in random + // order and we can't guarantee that we can access these. + if (Py_IsInitialized()) + PyRun_SimpleString("lldb.debugger = None; lldb.target = None; lldb.process = None; lldb.thread = None; lldb.frame = None"); +} + +bool +ScriptInterpreterPython::BreakpointCallbackFunction(void *baton, StoppointCallbackContext *context, user_id_t break_id, + user_id_t break_loc_id) +{ + BreakpointOptions::CommandData *bp_option_data = (BreakpointOptions::CommandData *) baton; + const char *python_function_name = bp_option_data->script_source.c_str(); + + if (!context) + return true; + + ExecutionContext exe_ctx (context->exe_ctx_ref); + Target *target = exe_ctx.GetTargetPtr(); + + if (!target) + return true; + + Debugger &debugger = target->GetDebugger(); + ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter(); + ScriptInterpreterPython *python_interpreter = (ScriptInterpreterPython *) script_interpreter; + + if (!script_interpreter) + return true; + + if (python_function_name && python_function_name[0]) + { + const StackFrameSP stop_frame_sp (exe_ctx.GetFrameSP()); + BreakpointSP breakpoint_sp = target->GetBreakpointByID (break_id); + if (breakpoint_sp) + { + const BreakpointLocationSP bp_loc_sp (breakpoint_sp->FindLocationByID (break_loc_id)); + + if (stop_frame_sp && bp_loc_sp) + { + bool ret_val = true; + { + Locker py_lock(python_interpreter, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + ret_val = LLDBSwigPythonBreakpointCallbackFunction(python_function_name, python_interpreter->m_dictionary_name.c_str(), + stop_frame_sp, bp_loc_sp); + } + return ret_val; + } + } + } + // We currently always true so we stop in case anything goes wrong when + // trying to call the script function + return true; +} + +bool +ScriptInterpreterPython::WatchpointCallbackFunction(void *baton, StoppointCallbackContext *context, user_id_t watch_id) +{ + WatchpointOptions::CommandData *wp_option_data = (WatchpointOptions::CommandData *) baton; + const char *python_function_name = wp_option_data->script_source.c_str(); + + if (!context) + return true; + + ExecutionContext exe_ctx (context->exe_ctx_ref); + Target *target = exe_ctx.GetTargetPtr(); + + if (!target) + return true; + + Debugger &debugger = target->GetDebugger(); + ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter(); + ScriptInterpreterPython *python_interpreter = (ScriptInterpreterPython *) script_interpreter; + + if (!script_interpreter) + return true; + + if (python_function_name && python_function_name[0]) + { + const StackFrameSP stop_frame_sp (exe_ctx.GetFrameSP()); + WatchpointSP wp_sp = target->GetWatchpointList().FindByID (watch_id); + if (wp_sp) + { + if (stop_frame_sp && wp_sp) + { + bool ret_val = true; + { + Locker py_lock(python_interpreter, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + ret_val = LLDBSwigPythonWatchpointCallbackFunction(python_function_name, python_interpreter->m_dictionary_name.c_str(), + stop_frame_sp, wp_sp); + } + return ret_val; + } + } + } + // We currently always true so we stop in case anything goes wrong when + // trying to call the script function + return true; +} + +size_t +ScriptInterpreterPython::CalculateNumChildren (const lldb::ScriptInterpreterObjectSP& implementor_sp) +{ + if (!implementor_sp) + return 0; + + void* implementor = implementor_sp->GetObject(); + + if (!implementor) + return 0; + + uint32_t ret_val = 0; + + { + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + ret_val = LLDBSwigPython_CalculateNumChildren(implementor); + } + + return ret_val; +} + +lldb::ValueObjectSP +ScriptInterpreterPython::GetChildAtIndex (const lldb::ScriptInterpreterObjectSP& implementor_sp, uint32_t idx) +{ + if (!implementor_sp) + return lldb::ValueObjectSP(); + + void* implementor = implementor_sp->GetObject(); + + if (!implementor) + return lldb::ValueObjectSP(); + + lldb::ValueObjectSP ret_val; + + { + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + void *child_ptr = LLDBSwigPython_GetChildAtIndex(implementor, idx); + if (child_ptr != nullptr && child_ptr != Py_None) + { + lldb::SBValue *sb_value_ptr = (lldb::SBValue *)LLDBSWIGPython_CastPyObjectToSBValue(child_ptr); + if (sb_value_ptr == nullptr) + Py_XDECREF(child_ptr); + else + ret_val = LLDBSWIGPython_GetValueObjectSPFromSBValue(sb_value_ptr); + } + else + { + Py_XDECREF(child_ptr); + } + } + + return ret_val; +} + +int +ScriptInterpreterPython::GetIndexOfChildWithName (const lldb::ScriptInterpreterObjectSP& implementor_sp, const char* child_name) +{ + if (!implementor_sp) + return UINT32_MAX; + + void* implementor = implementor_sp->GetObject(); + + if (!implementor) + return UINT32_MAX; + + int ret_val = UINT32_MAX; + + { + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + ret_val = LLDBSwigPython_GetIndexOfChildWithName(implementor, child_name); + } + + return ret_val; +} + +bool +ScriptInterpreterPython::UpdateSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor_sp) +{ + bool ret_val = false; + + if (!implementor_sp) + return ret_val; + + void* implementor = implementor_sp->GetObject(); + + if (!implementor) + return ret_val; + + { + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + ret_val = LLDBSwigPython_UpdateSynthProviderInstance(implementor); + } + + return ret_val; +} + +bool +ScriptInterpreterPython::MightHaveChildrenSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor_sp) +{ + bool ret_val = false; + + if (!implementor_sp) + return ret_val; + + void* implementor = implementor_sp->GetObject(); + + if (!implementor) + return ret_val; + + { + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + ret_val = LLDBSwigPython_MightHaveChildrenSynthProviderInstance(implementor); + } + + return ret_val; +} + +lldb::ValueObjectSP +ScriptInterpreterPython::GetSyntheticValue (const lldb::ScriptInterpreterObjectSP& implementor_sp) +{ + lldb::ValueObjectSP ret_val(nullptr); + + if (!implementor_sp) + return ret_val; + + void* implementor = implementor_sp->GetObject(); + + if (!implementor) + return ret_val; + + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + void *child_ptr = LLDBSwigPython_GetValueSynthProviderInstance(implementor); + if (child_ptr != nullptr && child_ptr != Py_None) + { + lldb::SBValue *sb_value_ptr = (lldb::SBValue *)LLDBSWIGPython_CastPyObjectToSBValue(child_ptr); + if (sb_value_ptr == nullptr) + Py_XDECREF(child_ptr); + else + ret_val = LLDBSWIGPython_GetValueObjectSPFromSBValue(sb_value_ptr); + } + else + { + Py_XDECREF(child_ptr); + } + + return ret_val; +} + +static std::string +ReadPythonBacktrace (PyObject* py_backtrace) +{ + PyObject *traceback_module = nullptr, *stringIO_module = nullptr, *stringIO_builder = nullptr, *stringIO_buffer = nullptr, + *printTB = nullptr, *printTB_args = nullptr, *printTB_result = nullptr, *stringIO_getvalue = nullptr, + *printTB_string = nullptr; + + std::string retval("backtrace unavailable"); + + if (py_backtrace && py_backtrace != Py_None) + { + traceback_module = PyImport_ImportModule("traceback"); + stringIO_module = PyImport_ImportModule("StringIO"); + + if (traceback_module && traceback_module != Py_None && stringIO_module && stringIO_module != Py_None) + { + stringIO_builder = PyObject_GetAttrString(stringIO_module, "StringIO"); + if (stringIO_builder && stringIO_builder != Py_None) + { + stringIO_buffer = PyObject_CallObject(stringIO_builder, nullptr); + if (stringIO_buffer && stringIO_buffer != Py_None) + { + printTB = PyObject_GetAttrString(traceback_module, "print_tb"); + if (printTB && printTB != Py_None) + { + printTB_args = Py_BuildValue("OOO",py_backtrace,Py_None,stringIO_buffer); + printTB_result = PyObject_CallObject(printTB, printTB_args); + stringIO_getvalue = PyObject_GetAttrString(stringIO_buffer, "getvalue"); + if (stringIO_getvalue && stringIO_getvalue != Py_None) + { + printTB_string = PyObject_CallObject (stringIO_getvalue,nullptr); + if (printTB_string && printTB_string != Py_None && PyString_Check(printTB_string)) + retval.assign(PyString_AsString(printTB_string)); + } + } + } + } + } + } + Py_XDECREF(traceback_module); + Py_XDECREF(stringIO_module); + Py_XDECREF(stringIO_builder); + Py_XDECREF(stringIO_buffer); + Py_XDECREF(printTB); + Py_XDECREF(printTB_args); + Py_XDECREF(printTB_result); + Py_XDECREF(stringIO_getvalue); + Py_XDECREF(printTB_string); + return retval; +} + +bool +ScriptInterpreterPython::RunScriptFormatKeyword(const char *impl_function, Process *process, std::string &output, Error &error) +{ + bool ret_val; + if (!process) + { + error.SetErrorString("no process"); + return false; + } + if (!impl_function || !impl_function[0]) + { + error.SetErrorString("no function to execute"); + return false; + } + { + ProcessSP process_sp(process->shared_from_this()); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + ret_val = LLDBSWIGPythonRunScriptKeywordProcess(impl_function, m_dictionary_name.c_str(), process_sp, output); + if (!ret_val) + error.SetErrorString("python script evaluation failed"); + } + return ret_val; +} + +bool +ScriptInterpreterPython::RunScriptFormatKeyword(const char *impl_function, Thread *thread, std::string &output, Error &error) +{ + bool ret_val; + if (!thread) + { + error.SetErrorString("no thread"); + return false; + } + if (!impl_function || !impl_function[0]) + { + error.SetErrorString("no function to execute"); + return false; + } + { + ThreadSP thread_sp(thread->shared_from_this()); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + ret_val = LLDBSWIGPythonRunScriptKeywordThread(impl_function, m_dictionary_name.c_str(), thread_sp, output); + if (!ret_val) + error.SetErrorString("python script evaluation failed"); + } + return ret_val; +} + +bool +ScriptInterpreterPython::RunScriptFormatKeyword(const char *impl_function, Target *target, std::string &output, Error &error) +{ + bool ret_val; + if (!target) + { + error.SetErrorString("no thread"); + return false; + } + if (!impl_function || !impl_function[0]) + { + error.SetErrorString("no function to execute"); + return false; + } + { + TargetSP target_sp(target->shared_from_this()); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + ret_val = LLDBSWIGPythonRunScriptKeywordTarget(impl_function, m_dictionary_name.c_str(), target_sp, output); + if (!ret_val) + error.SetErrorString("python script evaluation failed"); + } + return ret_val; +} + +bool +ScriptInterpreterPython::RunScriptFormatKeyword(const char *impl_function, StackFrame *frame, std::string &output, Error &error) +{ + bool ret_val; + if (!frame) + { + error.SetErrorString("no frame"); + return false; + } + if (!impl_function || !impl_function[0]) + { + error.SetErrorString("no function to execute"); + return false; + } + { + StackFrameSP frame_sp(frame->shared_from_this()); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + ret_val = LLDBSWIGPythonRunScriptKeywordFrame(impl_function, m_dictionary_name.c_str(), frame_sp, output); + if (!ret_val) + error.SetErrorString("python script evaluation failed"); + } + return ret_val; +} + +bool +ScriptInterpreterPython::RunScriptFormatKeyword(const char *impl_function, ValueObject *value, std::string &output, Error &error) +{ + bool ret_val; + if (!value) + { + error.SetErrorString("no value"); + return false; + } + if (!impl_function || !impl_function[0]) + { + error.SetErrorString("no function to execute"); + return false; + } + { + ValueObjectSP value_sp(value->GetSP()); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + ret_val = LLDBSWIGPythonRunScriptKeywordValue(impl_function, m_dictionary_name.c_str(), value_sp, output); + if (!ret_val) + error.SetErrorString("python script evaluation failed"); + } + return ret_val; +} + +uint64_t +replace_all(std::string &str, const std::string &oldStr, const std::string &newStr) +{ + size_t pos = 0; + uint64_t matches = 0; + while((pos = str.find(oldStr, pos)) != std::string::npos) + { + matches++; + str.replace(pos, oldStr.length(), newStr); + pos += newStr.length(); + } + return matches; +} + +bool +ScriptInterpreterPython::LoadScriptingModule(const char *pathname, bool can_reload, bool init_session, lldb_private::Error &error, + lldb::ScriptInterpreterObjectSP* module_sp) +{ + if (!pathname || !pathname[0]) + { + error.SetErrorString("invalid pathname"); + return false; + } + + lldb::DebuggerSP debugger_sp = m_interpreter.GetDebugger().shared_from_this(); + + { + FileSpec target_file(pathname, true); + std::string basename(target_file.GetFilename().GetCString()); + + StreamString command_stream; + + // Before executing Pyton code, lock the GIL. + Locker py_lock(this, Locker::AcquireLock | (init_session ? Locker::InitSession : 0) | Locker::NoSTDIN, + Locker::FreeAcquiredLock | (init_session ? Locker::TearDownSession : 0)); + + if (target_file.GetFileType() == FileSpec::eFileTypeInvalid || target_file.GetFileType() == FileSpec::eFileTypeUnknown) + { + // if not a valid file of any sort, check if it might be a filename still + // dot can't be used but / and \ can, and if either is found, reject + if (strchr(pathname,'\\') || strchr(pathname,'/')) + { + error.SetErrorString("invalid pathname"); + return false; + } + basename = pathname; // not a filename, probably a package of some sort, let it go through + } + else if (target_file.GetFileType() == FileSpec::eFileTypeDirectory || target_file.GetFileType() == FileSpec::eFileTypeRegular || + target_file.GetFileType() == FileSpec::eFileTypeSymbolicLink) + { + std::string directory(target_file.GetDirectory().GetCString()); + replace_all(directory,"'","\\'"); + + // now make sure that Python has "directory" in the search path + StreamString command_stream; + 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)).Success(); + if (!syspath_retval) + { + error.SetErrorString("Python sys.path handling failed"); + return false; + } + + // strip .py or .pyc extension + ConstString extension = target_file.GetFileNameExtension(); + if (extension) + { + if (::strcmp(extension.GetCString(), "py") == 0) + basename.resize(basename.length()-3); + else if(::strcmp(extension.GetCString(), "pyc") == 0) + basename.resize(basename.length()-4); + } + } + else + { + error.SetErrorString("no known way to import this module specification"); + return false; + } + + // check if the module is already import-ed + command_stream.Clear(); + command_stream.Printf("sys.modules.__contains__('%s')",basename.c_str()); + bool does_contain = false; + // 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(), ScriptInterpreterPython::eScriptReturnTypeBool, &does_contain, + ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false).SetSetLLDBGlobals(false)) && + does_contain); + // 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 = !(GetSessionDictionary().GetItemForKey(basename.c_str()).IsNULLOrNone()); + + bool was_imported = (was_imported_globally || was_imported_locally); + + if (was_imported == true && can_reload == false) + { + error.SetErrorString("module already imported"); + return false; + } + + // now actually do the import + command_stream.Clear(); + + if (was_imported) + { + if (!was_imported_locally) + command_stream.Printf("import %s ; reload(%s)",basename.c_str(),basename.c_str()); + else + command_stream.Printf("reload(%s)",basename.c_str()); + } + else + command_stream.Printf("import %s",basename.c_str()); + + 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) + if (!LLDBSwigPythonCallModuleInit(basename.c_str(), m_dictionary_name.c_str(), debugger_sp)) + { + error.SetErrorString("calling __lldb_init_module failed"); + return false; + } + + if (module_sp) + { + // everything went just great, now set the module object + command_stream.Clear(); + command_stream.Printf("%s",basename.c_str()); + void* module_pyobj = nullptr; + if (ExecuteOneLineWithReturn(command_stream.GetData(), ScriptInterpreter::eScriptReturnTypeOpaqueObject, &module_pyobj) && + module_pyobj) + *module_sp = MakeScriptObject(module_pyobj); + } + + return true; + } +} + +bool +ScriptInterpreterPython::IsReservedWord (const char* word) +{ + StreamString command_stream; + command_stream.Printf("keyword.iskeyword('%s')", word); + bool result; + ExecuteScriptOptions options; + options.SetEnableIO(false); + options.SetMaskoutErrors(true); + options.SetSetLLDBGlobals(false); + if (ExecuteOneLineWithReturn(command_stream.GetData(), ScriptInterpreter::eScriptReturnTypeBool, &result, options)) + return result; + return false; +} + +lldb::ScriptInterpreterObjectSP +ScriptInterpreterPython::MakeScriptObject (void* object) +{ + return lldb::ScriptInterpreterObjectSP(new ScriptInterpreterPythonObject(object)); +} + +ScriptInterpreterPython::SynchronicityHandler::SynchronicityHandler(lldb::DebuggerSP debugger_sp, ScriptedCommandSynchronicity synchro) + : m_debugger_sp(debugger_sp) + , m_synch_wanted(synchro) + , m_old_asynch(debugger_sp->GetAsyncExecution()) +{ + if (m_synch_wanted == eScriptedCommandSynchronicitySynchronous) + m_debugger_sp->SetAsyncExecution(false); + else if (m_synch_wanted == eScriptedCommandSynchronicityAsynchronous) + m_debugger_sp->SetAsyncExecution(true); +} + +ScriptInterpreterPython::SynchronicityHandler::~SynchronicityHandler() +{ + if (m_synch_wanted != eScriptedCommandSynchronicityCurrentValue) + m_debugger_sp->SetAsyncExecution(m_old_asynch); +} + +bool +ScriptInterpreterPython::RunScriptBasedCommand(const char *impl_function, const char *args, ScriptedCommandSynchronicity synchronicity, + lldb_private::CommandReturnObject &cmd_retobj, Error &error, + const lldb_private::ExecutionContext& exe_ctx) +{ + if (!impl_function) + { + error.SetErrorString("no function to execute"); + return false; + } + + lldb::DebuggerSP debugger_sp = m_interpreter.GetDebugger().shared_from_this(); + lldb::ExecutionContextRefSP exe_ctx_ref_sp(new ExecutionContextRef(exe_ctx)); + + if (!debugger_sp.get()) + { + error.SetErrorString("invalid Debugger pointer"); + return false; + } + + bool ret_val = false; + + std::string err_msg; + + { + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | (cmd_retobj.GetInteractive() ? 0 : Locker::NoSTDIN), + Locker::FreeLock | Locker::TearDownSession); + + SynchronicityHandler synch_handler(debugger_sp, synchronicity); + + ret_val = LLDBSwigPythonCallCommand(impl_function, m_dictionary_name.c_str(), debugger_sp, args, cmd_retobj, exe_ctx_ref_sp); + } + + if (!ret_val) + error.SetErrorString("unable to execute script function"); + else + error.Clear(); + + return ret_val; +} + +// in Python, a special attribute __doc__ contains the docstring +// for an object (function, method, class, ...) if any is defined +// Otherwise, the attribute's value is None +bool +ScriptInterpreterPython::GetDocumentationForItem(const char* item, std::string& dest) +{ + dest.clear(); + if (!item || !*item) + return false; + std::string command(item); + command += ".__doc__"; + + char* result_ptr = nullptr; // Python is going to point this to valid data if ExecuteOneLineWithReturn returns successfully + + if (ExecuteOneLineWithReturn(command.c_str(), ScriptInterpreter::eScriptReturnTypeCharStrOrNone, &result_ptr, + ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false))) + { + if (result_ptr) + dest.assign(result_ptr); + return true; + } + else + { + StreamString str_stream; + str_stream.Printf("Function %s was not found. Containing module might be missing.",item); + dest.assign(str_stream.GetData()); + return false; + } +} + +std::unique_ptr +ScriptInterpreterPython::AcquireInterpreterLock () +{ + std::unique_ptr py_lock( + new Locker(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN, Locker::FreeLock | Locker::TearDownSession)); + return py_lock; +} + +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 + // settings so we can restore them. + TerminalState stdin_tty_state; + stdin_tty_state.Save(STDIN_FILENO, false); + + PyGILState_STATE gstate; + Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT | LIBLLDB_LOG_VERBOSE)); + bool threads_already_initialized = false; + if (PyEval_ThreadsInitialized()) + { + gstate = PyGILState_Ensure (); + if (log) + log->Printf("Ensured PyGILState. Previous state = %slocked\n", gstate == PyGILState_UNLOCKED ? "un" : ""); + threads_already_initialized = true; + } + else + { + // InitThreads acquires the GIL if it hasn't been called before. + PyEval_InitThreads (); + } + Py_InitializeEx (0); + + // Initialize SWIG after setting up python + init_lldb(); + + // Update the path python uses to search for modules to include the current directory. + + PyRun_SimpleString ("import sys"); + PyRun_SimpleString ("sys.path.append ('.')"); + + // Find the module that owns this code and use that path we get to + // set the sys.path appropriately. + + FileSpec file_spec; + char python_dir_path[PATH_MAX]; + if (HostInfo::GetLLDBPath(ePathTypePythonDir, file_spec)) + { + std::string python_path("sys.path.insert(0,\""); + size_t orig_len = python_path.length(); + if (file_spec.GetPath(python_dir_path, sizeof (python_dir_path))) + { + python_path.append (python_dir_path); + python_path.append ("\")"); + PyRun_SimpleString (python_path.c_str()); + python_path.resize (orig_len); + } + + if (HostInfo::GetLLDBPath(ePathTypeLLDBShlibDir, file_spec)) + { + if (file_spec.GetPath(python_dir_path, sizeof (python_dir_path))) + { + python_path.append (python_dir_path); + python_path.append ("\")"); + PyRun_SimpleString (python_path.c_str()); + python_path.resize (orig_len); + } + } + } + + // Importing 'lldb' module calls SBDebugger::Initialize, which calls Debugger::Initialize, which increments a + // global debugger ref-count; therefore we need to check the ref-count before and after importing lldb, and if the + // ref-count increased we need to call Debugger::Terminate here to decrement the ref-count so that when the final + // call to Debugger::Terminate is made, the ref-count has the correct value. + + int old_count = Debugger::TestDebuggerRefCount (); + + PyRun_SimpleString("sys.dont_write_bytecode = 1; import lldb.embedded_interpreter; from lldb.embedded_interpreter import " + "run_python_interpreter; from lldb.embedded_interpreter import run_one_line"); + + int new_count = Debugger::TestDebuggerRefCount (); + + if (new_count > old_count) + Debugger::Terminate (); + + if (threads_already_initialized) + { + if (log) + log->Printf("Releasing PyGILState. Returning to state = %slocked\n", gstate == PyGILState_UNLOCKED ? "un" : ""); + PyGILState_Release (gstate); + } + else + { + // We initialized the threads in this function, just unlock the GIL. + PyEval_SaveThread(); + } + + stdin_tty_state.Restore(); +} + +//void +//ScriptInterpreterPython::Terminate () +//{ +// // We are intentionally NOT calling Py_Finalize here (this would be the logical place to call it). Calling +// // Py_Finalize here causes test suite runs to seg fault: The test suite runs in Python. It registers +// // SBDebugger::Terminate to be called 'at_exit'. When the test suite Python harness finishes up, it calls +// // Py_Finalize, which calls all the 'at_exit' registered functions. SBDebugger::Terminate calls Debugger::Terminate, +// // which calls lldb::Terminate, which calls ScriptInterpreter::Terminate, which calls +// // ScriptInterpreterPython::Terminate. So if we call Py_Finalize here, we end up with Py_Finalize being called from +// // within Py_Finalize, which results in a seg fault. +// // +// // Since this function only gets called when lldb is shutting down and going away anyway, the fact that we don't +// // actually call Py_Finalize should not cause any problems (everything should shut down/go away anyway when the +// // process exits). +// // +//// Py_Finalize (); +//} + +#endif // #ifdef LLDB_DISABLE_PYTHON Index: source/ScriptInterpreter/Python/embedded_interpreter.py =================================================================== --- /dev/null +++ source/ScriptInterpreter/Python/embedded_interpreter.py @@ -0,0 +1,112 @@ +import __builtin__ +import code +import lldb +import sys +import traceback + +try: + import readline + import rlcompleter +except ImportError: + have_readline = False +except AttributeError: + # This exception gets hit by the rlcompleter when Linux is using + # the readline suppression import. + 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') + +g_builtin_override_called = False + +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 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') + +# 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 + +g_run_one_line_str = None + + +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 readfunc_stdio(prompt): + sys.stdout.write(prompt) + return sys.stdin.readline().rstrip() + +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) Index: source/ScriptInterpreter/ScriptInterpreter.cpp =================================================================== --- /dev/null +++ source/ScriptInterpreter/ScriptInterpreter.cpp @@ -0,0 +1,160 @@ +//===-- ScriptInterpreter.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/lldb-python.h" + +#include "lldb/ScriptInterpreter/ScriptInterpreter.h" + +#include +#include +#include + +#include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Stream.h" +#include "lldb/Core/StringList.h" +#include "lldb/Host/Mutex.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/ScriptInterpreter/ScriptInterpreterNone.h" +#ifndef LLDB_DISABLE_PYTHON +#include "lldb/ScriptInterpreter/Python/ScriptInterpreterPython.h" +#endif +#include "lldb/Utility/PseudoTerminal.h" + +using namespace lldb; +using namespace lldb_private; + +namespace +{ +ScriptInterpreterNone *g_none_interpreter = nullptr; +#ifndef LLDB_DISABLE_PYTHON +ScriptInterpreterPython *g_python_interpreter = nullptr; +#endif +} + +ScriptInterpreter::ScriptInterpreter(CommandInterpreter &interpreter, lldb::ScriptLanguage script_lang) + : m_interpreter(interpreter) + , m_script_lang(script_lang) +{ +} + +ScriptInterpreter::~ScriptInterpreter() +{ +} + +CommandInterpreter & +ScriptInterpreter::GetCommandInterpreter() +{ + return m_interpreter; +} + +void +ScriptInterpreter::CollectDataForBreakpointCommandCallback(std::vector &bp_options_vec, CommandReturnObject &result) +{ + result.SetStatus(eReturnStatusFailed); + result.AppendError("ScriptInterpreter::GetScriptCommands(StringList &) is not implemented."); +} + +void +ScriptInterpreter::CollectDataForWatchpointCommandCallback(WatchpointOptions *bp_options, CommandReturnObject &result) +{ + result.SetStatus(eReturnStatusFailed); + result.AppendError("ScriptInterpreter::GetScriptCommands(StringList &) is not implemented."); +} + +std::string +ScriptInterpreter::LanguageToString(lldb::ScriptLanguage language) +{ + std::string return_value; + + switch (language) + { + case eScriptLanguageNone: + return_value = "None"; + break; + case eScriptLanguagePython: + return_value = "Python"; + break; + } + + return return_value; +} + +Error +ScriptInterpreter::SetBreakpointCommandCallback(std::vector &bp_options_vec, const char *callback_text) +{ + Error return_error; + for (BreakpointOptions *bp_options : bp_options_vec) + { + return_error = SetBreakpointCommandCallback(bp_options, callback_text); + if (return_error.Success()) + break; + } + return return_error; +} + +void +ScriptInterpreter::SetBreakpointCommandCallbackFunction(std::vector &bp_options_vec, const char *function_name) +{ + for (BreakpointOptions *bp_options : bp_options_vec) + { + SetBreakpointCommandCallbackFunction(bp_options, function_name); + } +} + +std::unique_ptr +ScriptInterpreter::AcquireInterpreterLock() +{ + return std::unique_ptr(new ScriptInterpreterLocker()); +} + +ScriptInterpreter * +ScriptInterpreter::GetScriptInterpreter(lldb::ScriptLanguage script_lang, CommandInterpreter &command_interpreter, bool can_create) +{ + // + // we need to protect the initialization of the script interpreter + // otherwise we could end up with two threads both trying to create + // their instance of it, and for some languages (e.g. Python) + // this is a bulletproof recipe for disaster! + // this needs to be a function-level static because multiple Debugger + // instances living in the same process still need to be isolated and + // not try to initialize the script interpreter concurrently. + static Mutex g_interpreter_mutex(Mutex::eMutexTypeRecursive); + Mutex::Locker interpreter_lock(g_interpreter_mutex); + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SCRIPT)); + if (log) + log->Printf("Initializing the ScriptInterpreter now\n"); + + switch (script_lang) + { + case eScriptLanguagePython: +#ifndef LLDB_DISABLE_PYTHON + if (!g_python_interpreter && can_create) + g_python_interpreter = new ScriptInterpreterPython(command_interpreter); + return g_python_interpreter; +#else +// Fall through to the None case when python is disabled +#endif + case eScriptLanguageNone: + if (!g_none_interpreter && can_create) + g_none_interpreter = new ScriptInterpreterNone(command_interpreter); + return g_none_interpreter; + }; + + return nullptr; +} + +void +ScriptInterpreter::InitializePrivate() +{ +#ifndef LLDB_DISABLE_PYTHON + ScriptInterpreterPython::InitializePrivate(); +#endif +} Index: source/ScriptInterpreter/ScriptInterpreterNone.cpp =================================================================== --- /dev/null +++ source/ScriptInterpreter/ScriptInterpreterNone.cpp @@ -0,0 +1,40 @@ +//===-- ScriptInterpreterNone.cpp -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/ScriptInterpreter/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" + +using namespace lldb; +using namespace lldb_private; + +ScriptInterpreterNone::ScriptInterpreterNone(CommandInterpreter &interpreter) + : ScriptInterpreter(interpreter, eScriptLanguageNone) +{ +} + +ScriptInterpreterNone::~ScriptInterpreterNone() +{ +} + +bool +ScriptInterpreterNone::ExecuteOneLine(const char *command, CommandReturnObject *, const ExecuteScriptOptions &) +{ + m_interpreter.GetDebugger().GetErrorFile()->PutCString("error: there is no embedded script interpreter in this mode.\n"); + return false; +} + +void +ScriptInterpreterNone::ExecuteInterpreterLoop() +{ + m_interpreter.GetDebugger().GetErrorFile()->PutCString("error: there is no embedded script interpreter in this mode.\n"); +} Index: source/Target/ThreadPlanPython.cpp =================================================================== --- source/Target/ThreadPlanPython.cpp +++ source/Target/ThreadPlanPython.cpp @@ -19,8 +19,7 @@ #include "lldb/Core/Log.h" #include "lldb/Core/State.h" #include "lldb/Interpreter/CommandInterpreter.h" -#include "lldb/Interpreter/ScriptInterpreter.h" -#include "lldb/Interpreter/ScriptInterpreterPython.h" +#include "lldb/ScriptInterpreter/ScriptInterpreter.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlan.h" Index: source/lldb.cpp =================================================================== --- source/lldb.cpp +++ source/lldb.cpp @@ -20,7 +20,7 @@ #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/Mutex.h" -#include "lldb/Interpreter/ScriptInterpreterPython.h" +#include "lldb/ScriptInterpreter/ScriptInterpreter.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" @@ -177,8 +177,8 @@ PlatformAndroid::Initialize(); SymbolFileDWARFDebugMap::Initialize(); ItaniumABILanguageRuntime::Initialize(); + ScriptInterpreter::InitializePrivate(); #ifndef LLDB_DISABLE_PYTHON - ScriptInterpreterPython::InitializePrivate(); OperatingSystemPython::Initialize(); #endif JITLoaderGDB::Initialize(); Index: tools/driver/CMakeLists.txt =================================================================== --- tools/driver/CMakeLists.txt +++ tools/driver/CMakeLists.txt @@ -2,6 +2,8 @@ add_lldb_executable(lldb Driver.cpp Platform.cpp + ADDITIONAL_HEADER_DIRS + ${LLDB_INCLUDE_ROOT}/lldb ) if ( CMAKE_SYSTEM_NAME MATCHES "Windows" ) Index: tools/lldb-server/CMakeLists.txt =================================================================== --- tools/lldb-server/CMakeLists.txt +++ tools/lldb-server/CMakeLists.txt @@ -2,19 +2,19 @@ if ( CMAKE_SYSTEM_NAME MATCHES "Linux" ) include_directories( - ../../source/Plugins/Process/Linux - ../../source/Plugins/Process/POSIX + ${LLDB_SOURCE_ROOT}/Plugins/Process/Linux + ${LLDB_SOURCE_ROOT}/Plugins/Process/POSIX ) endif () if ( CMAKE_SYSTEM_NAME MATCHES "FreeBSD" ) include_directories( - ../../source/Plugins/Process/FreeBSD - ../../source/Plugins/Process/POSIX + ${LLDB_SOURCE_ROOT}/Plugins/Process/FreeBSD + ${LLDB_SOURCE_ROOT}/Plugins/Process/POSIX ) endif () -include_directories(../../source) +include_directories(${LLDB_SOURCE_ROOT}) include(../../cmake/LLDBDependencies.cmake) @@ -31,8 +31,10 @@ lldb-server.cpp lldb-gdbserver.cpp lldb-platform.cpp - ../../source/lldb-log.cpp - ../../source/lldb.cpp + ${LLDB_SOURCE_ROOT}/lldb-log.cpp + ${LLDB_SOURCE_ROOT}/lldb.cpp + $ + ${LLDB_WRAP_PYTHON} ) # The Darwin linker doesn't understand --start-group/--end-group.