Index: include/lldb/API/SBCommandInterpreter.h =================================================================== --- include/lldb/API/SBCommandInterpreter.h +++ include/lldb/API/SBCommandInterpreter.h @@ -97,6 +97,9 @@ static bool EventIsCommandInterpreterEvent (const lldb::SBEvent &event); + + static void + InitializeScriptInterpreter(); bool IsValid() const; Index: include/lldb/API/SystemInitializerFull.h =================================================================== --- include/lldb/API/SystemInitializerFull.h +++ include/lldb/API/SystemInitializerFull.h @@ -33,7 +33,6 @@ private: void InitializeSWIG(); - void TerminateSWIG(); }; } Index: include/lldb/Core/PluginManager.h =================================================================== --- include/lldb/Core/PluginManager.h +++ include/lldb/Core/PluginManager.h @@ -296,6 +296,23 @@ GetProcessPluginDescriptionAtIndex (uint32_t idx); //------------------------------------------------------------------ + // ScriptInterpreter + //------------------------------------------------------------------ + static bool + RegisterPlugin(const ConstString &name, const char *description, lldb::ScriptLanguage script_lang, + ScriptInterpreterCreateInstance create_callback); + + static bool + UnregisterPlugin(ScriptInterpreterCreateInstance create_callback); + + static ScriptInterpreterCreateInstance + GetScriptInterpreterCreateCallbackAtIndex(uint32_t idx); + + static lldb::ScriptInterpreterSP + GetScriptInterpreterForLanguage(lldb::ScriptLanguage script_lang, + CommandInterpreter &interpreter); + + //------------------------------------------------------------------ // SymbolFile //------------------------------------------------------------------ static bool 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" @@ -520,7 +521,10 @@ GetOptionArgumentPosition (const char *in_string); ScriptInterpreter * - GetScriptInterpreter (bool can_create = true); + GetScriptInterpreter(bool can_create = true); + + void + SetScriptInterpreter(); void SkipLLDBInitFiles (bool skip_lldbinit_files) @@ -709,7 +713,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::ScriptInterpreterSP m_script_interpreter_sp; 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,280 +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/StructuredData.h" -#include "lldb/Core/Flags.h" -#include "lldb/Interpreter/OptionValue.h" -#include "lldb/lldb-python.h" - -namespace lldb_private { -class PythonString; -class PythonList; -class PythonDictionary; -class PythonObject; -class PythonInteger; - -class StructuredPythonObject : public StructuredData::Generic -{ - public: - StructuredPythonObject() - : StructuredData::Generic() - { - } - - StructuredPythonObject(void *obj) - : StructuredData::Generic(obj) - { - Py_XINCREF(GetValue()); - } - - virtual ~StructuredPythonObject() - { - if (Py_IsInitialized()) - Py_XDECREF(GetValue()); - SetValue(nullptr); - } - - bool - IsValid() const override - { - return GetValue() && GetValue() != Py_None; - } - - void Dump(Stream &s) const override; - - private: - DISALLOW_COPY_AND_ASSIGN(StructuredPythonObject); -}; - -enum class PyObjectType -{ - Unknown, - None, - Integer, - Dictionary, - List, - String -}; - - 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); - } - - 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; - } - - PyObjectType GetObjectType() const; - - PythonString - Repr (); - - PythonString - Str (); - - explicit operator bool () const - { - return m_py_obj != NULL; - } - - bool - IsNULLOrNone () const; - - StructuredData::ObjectSP CreateStructuredObject() const; - - protected: - PyObject* m_py_obj; - }; - - class PythonString: public PythonObject - { - public: - PythonString (); - PythonString (PyObject *o); - PythonString (const PythonObject &object); - PythonString (llvm::StringRef string); - PythonString (const char *string); - virtual ~PythonString (); - - virtual bool - Reset (PyObject* py_obj = NULL); - - llvm::StringRef - GetString() const; - - size_t - GetSize() const; - - void SetString(llvm::StringRef string); - - StructuredData::StringSP CreateStructuredString() const; - }; - - class PythonInteger: public PythonObject - { - public: - - PythonInteger (); - PythonInteger (PyObject* py_obj); - PythonInteger (const PythonObject &object); - PythonInteger (int64_t value); - virtual ~PythonInteger (); - - virtual bool - Reset (PyObject* py_obj = NULL); - - int64_t GetInteger() const; - - void - SetInteger (int64_t value); - - StructuredData::IntegerSP CreateStructuredInteger() const; - }; - - class PythonList: public PythonObject - { - public: - - PythonList (bool create_empty); - PythonList (PyObject* py_obj); - PythonList (const PythonObject &object); - PythonList (uint32_t count); - virtual ~PythonList (); - - virtual bool - Reset (PyObject* py_obj = NULL); - - uint32_t GetSize() const; - - PythonObject GetItemAtIndex(uint32_t index) const; - - void - SetItemAtIndex (uint32_t index, const PythonObject &object); - - void - AppendItem (const PythonObject &object); - - StructuredData::ArraySP CreateStructuredArray() const; - }; - - class PythonDictionary: public PythonObject - { - public: - - explicit PythonDictionary (bool create_empty); - PythonDictionary (PyObject* object); - PythonDictionary (const PythonObject &object); - virtual ~PythonDictionary (); - - virtual bool - Reset (PyObject* object = NULL); - - uint32_t GetSize() const; - - 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); - - StructuredData::DictionarySP CreateStructuredDictionary() const; - }; - -} // namespace lldb_private - -#endif // liblldb_PythonDataObjects_h_ Index: include/lldb/Interpreter/ScriptInterpreter.h =================================================================== --- include/lldb/Interpreter/ScriptInterpreter.h +++ include/lldb/Interpreter/ScriptInterpreter.h @@ -14,6 +14,7 @@ #include "lldb/Core/Broadcaster.h" #include "lldb/Core/Error.h" +#include "lldb/Core/PluginInterface.h" #include "lldb/Core/StructuredData.h" #include "lldb/Utility/PseudoTerminal.h" @@ -36,8 +37,7 @@ DISALLOW_COPY_AND_ASSIGN (ScriptInterpreterLocker); }; - -class ScriptInterpreter +class ScriptInterpreter : public PluginInterface { public: 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,563 +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: - 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* (*SWIGPythonCreateCommandObject) (const char *python_class_name, - const char *session_dictionary_name, - const lldb::DebuggerSP debugger_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 size_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 (*SWIGPythonCallCommandObject) (void *implementor, - 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); - - 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; - - StructuredData::ObjectSP CreateSyntheticScriptedProvider(const char *class_name, lldb::ValueObjectSP valobj) override; - - StructuredData::GenericSP CreateScriptCommandObject (const char *class_name) override; - - StructuredData::ObjectSP CreateScriptedThreadPlan(const char *class_name, lldb::ThreadPlanSP thread_plan) override; - - bool ScriptedThreadPlanExplainsStop(StructuredData::ObjectSP implementor_sp, Event *event, bool &script_error) override; - bool ScriptedThreadPlanShouldStop(StructuredData::ObjectSP implementor_sp, Event *event, bool &script_error) override; - lldb::StateType ScriptedThreadPlanGetRunState(StructuredData::ObjectSP implementor_sp, bool &script_error) override; - - StructuredData::GenericSP OSPlugin_CreatePluginObject(const char *class_name, lldb::ProcessSP process_sp) override; - - StructuredData::DictionarySP OSPlugin_RegisterInfo(StructuredData::ObjectSP os_plugin_object_sp) override; - - StructuredData::ArraySP OSPlugin_ThreadsInfo(StructuredData::ObjectSP os_plugin_object_sp) override; - - StructuredData::StringSP OSPlugin_RegisterContextData(StructuredData::ObjectSP os_plugin_object_sp, lldb::tid_t thread_id) override; - - StructuredData::DictionarySP OSPlugin_CreateThread(StructuredData::ObjectSP os_plugin_object_sp, lldb::tid_t tid, - lldb::addr_t context) override; - - StructuredData::ObjectSP LoadPluginModule(const FileSpec &file_spec, lldb_private::Error &error) override; - - StructuredData::DictionarySP GetDynamicSettings(StructuredData::ObjectSP plugin_module_sp, Target *target, const char *setting_name, - lldb_private::Error &error) override; - - size_t CalculateNumChildren(const StructuredData::ObjectSP &implementor) override; - - lldb::ValueObjectSP GetChildAtIndex(const StructuredData::ObjectSP &implementor, uint32_t idx) override; - - int GetIndexOfChildWithName(const StructuredData::ObjectSP &implementor, const char *child_name) override; - - bool UpdateSynthProviderInstance(const StructuredData::ObjectSP &implementor) override; - - bool MightHaveChildrenSynthProviderInstance(const StructuredData::ObjectSP &implementor) override; - - lldb::ValueObjectSP GetSyntheticValue(const StructuredData::ObjectSP &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; - - bool - RunScriptBasedCommand (StructuredData::GenericSP impl_obj_sp, - 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, StructuredData::ObjectSP &callee_wrapper_sp, - const TypeSummaryOptions &options, std::string &retval) override; - - void - Clear () override; - - bool - GetDocumentationForItem (const char* item, std::string& dest) override; - - bool - GetShortHelpForCommandObject(StructuredData::GenericSP cmd_obj_sp, std::string& dest) override; - - uint32_t - GetFlagsForCommandObject (StructuredData::GenericSP cmd_obj_sp) override; - - bool - GetLongHelpForCommandObject(StructuredData::GenericSP cmd_obj_sp, 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, - StructuredData::ObjectSP *module_sp = nullptr) override; - - bool - IsReservedWord (const char* word) 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); - - 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, - SWIGPythonCreateCommandObject swig_create_cmd, - 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, - SWIGPythonCallCommandObject swig_call_command_object, - 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(); - }; - -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: - enum class AddLocation - { - Beginning, - End - }; - - static void AddToSysPath(AddLocation location, std::string path); - - 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/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 @@ -376,6 +376,8 @@ #ifndef LLDB_DISABLE_PYTHON typedef std::shared_ptr ScriptSummaryFormatSP; #endif // #ifndef LLDB_DISABLE_PYTHON + typedef std::shared_ptr ScriptInterpreterSP; + typedef std::unique_ptr ScriptInterpreterUP; typedef std::shared_ptr SectionSP; typedef std::unique_ptr SectionListUP; typedef std::weak_ptr SectionWP; Index: include/lldb/lldb-private-interfaces.h =================================================================== --- include/lldb/lldb-private-interfaces.h +++ include/lldb/lldb-private-interfaces.h @@ -33,6 +33,7 @@ typedef SystemRuntime *(*SystemRuntimeCreateInstance) (Process *process); typedef lldb::PlatformSP (*PlatformCreateInstance) (bool force, const ArchSpec *arch); typedef lldb::ProcessSP (*ProcessCreateInstance) (Target &target, Listener &listener, const FileSpec *crash_file_path); + typedef lldb::ScriptInterpreterSP (*ScriptInterpreterCreateInstance)(CommandInterpreter &interpreter); typedef SymbolFile* (*SymbolFileCreateInstance) (ObjectFile* obj_file); typedef SymbolVendor* (*SymbolVendorCreateInstance) (const lldb::ModuleSP &module_sp, lldb_private::Stream *feedback_strm); // Module can be NULL for default system symbol vendor typedef bool (*BreakpointHitCallback) (void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id); Index: include/lldb/lldb-python.h =================================================================== --- include/lldb/lldb-python.h +++ /dev/null @@ -1,31 +0,0 @@ -//===-- lldb-python.h --------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_lldb_python_h_ -#define LLDB_lldb_python_h_ - -// Python.h needs to be included before any system headers in order to avoid redefinition of macros - -#ifdef LLDB_DISABLE_PYTHON -// Python is disabled in this build -#else - #if defined(__linux__) - // features.h will define _POSIX_C_SOURCE if _GNU_SOURCE is defined. This value - // may be different from the value that Python defines it to be which results - // in a warning. Undefine _POSIX_C_SOURCE before including Python.h The same - // holds for _XOPEN_SOURCE. - #undef _POSIX_C_SOURCE - #undef _XOPEN_SOURCE - #endif - - // Include python for non windows machines - #include -#endif // LLDB_DISABLE_PYTHON - -#endif // LLDB_lldb_python_h_ Index: lldb.xcodeproj/project.pbxproj =================================================================== --- lldb.xcodeproj/project.pbxproj +++ lldb.xcodeproj/project.pbxproj @@ -426,8 +426,6 @@ 2689008513353E2200698AC0 /* CommandReturnObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F0A10F1B8DD00F91463 /* CommandReturnObject.cpp */; }; 2689008613353E2200698AC0 /* Options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E8610F1B85900F91463 /* Options.cpp */; }; 2689008713353E2200698AC0 /* ScriptInterpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A82010B10FFB49800182560 /* ScriptInterpreter.cpp */; }; - 2689008813353E2200698AC0 /* ScriptInterpreterNone.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A2771FC1135A37500E6ADB6 /* ScriptInterpreterNone.cpp */; }; - 2689008913353E2200698AC0 /* ScriptInterpreterPython.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F0C10F1B8DD00F91463 /* ScriptInterpreterPython.cpp */; }; 2689008D13353E4200698AC0 /* DynamicLoaderMacOSXDYLD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C897A10F57C5600BB2B04 /* DynamicLoaderMacOSXDYLD.cpp */; }; 2689008E13353E4200698AC0 /* DynamicLoaderStatic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 268A683D1321B53B000E3FB8 /* DynamicLoaderStatic.cpp */; }; 2689009613353E4200698AC0 /* ObjectContainerBSDArchive.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A3B4AC1181454800381BC2 /* ObjectContainerBSDArchive.cpp */; }; @@ -644,6 +642,14 @@ 3F8169311ABB7A6D001DA9DF /* SystemInitializer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3F81692E1ABB7A6D001DA9DF /* SystemInitializer.cpp */; }; 3F8169321ABB7A6D001DA9DF /* SystemInitializerCommon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3F81692F1ABB7A6D001DA9DF /* SystemInitializerCommon.cpp */; }; 3F8169331ABB7A6D001DA9DF /* SystemLifetimeManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3F8169301ABB7A6D001DA9DF /* SystemLifetimeManager.cpp */; }; + 3FBA69DF1B6067020008F44A /* ScriptInterpreterNone.cpp in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3FBA69DD1B6067020008F44A /* ScriptInterpreterNone.cpp */; }; + 3FBA69E01B6067020008F44A /* ScriptInterpreterNone.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3FBA69DE1B6067020008F44A /* ScriptInterpreterNone.h */; }; + 3FBA69E11B6067120008F44A /* ScriptInterpreterNone.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3FBA69DD1B6067020008F44A /* ScriptInterpreterNone.cpp */; }; + 3FBA69E71B60672A0008F44A /* lldb-python.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3FBA69E21B60672A0008F44A /* lldb-python.h */; }; + 3FBA69E91B60672A0008F44A /* PythonDataObjects.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3FBA69E41B60672A0008F44A /* PythonDataObjects.h */; }; + 3FBA69EB1B60672A0008F44A /* ScriptInterpreterPython.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3FBA69E61B60672A0008F44A /* ScriptInterpreterPython.h */; }; + 3FBA69EC1B6067430008F44A /* PythonDataObjects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3FBA69E31B60672A0008F44A /* PythonDataObjects.cpp */; }; + 3FBA69ED1B60674B0008F44A /* ScriptInterpreterPython.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3FBA69E51B60672A0008F44A /* ScriptInterpreterPython.cpp */; }; 3FDFDDBD199C3A06009756A7 /* FileAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3FDFDDBC199C3A06009756A7 /* FileAction.cpp */; }; 3FDFDDBF199D345E009756A7 /* FileCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3FDFDDBE199D345E009756A7 /* FileCache.cpp */; }; 3FDFDDC6199D37ED009756A7 /* FileSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3FDFDDC5199D37ED009756A7 /* FileSystem.cpp */; }; @@ -772,7 +778,6 @@ 94D6A0AB16CEB55F00833B6E /* NSDictionary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94D6A0A816CEB55F00833B6E /* NSDictionary.cpp */; }; 94D6A0AC16CEB55F00833B6E /* NSSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94D6A0A916CEB55F00833B6E /* NSSet.cpp */; }; 94E829CA152D33C1006F96A3 /* lldb-server in Resources */ = {isa = PBXBuildFile; fileRef = 26DC6A101337FE6900FF7998 /* lldb-server */; }; - 94EA1D5C15E6C9B400D4171A /* PythonDataObjects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94EA1D5B15E6C9B400D4171A /* PythonDataObjects.cpp */; }; 94EA27CE17DE91750070F505 /* LibCxxUnorderedMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94EA27CD17DE91750070F505 /* LibCxxUnorderedMap.cpp */; }; 94F48F251A01C687005C0EC6 /* StringPrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94F48F241A01C687005C0EC6 /* StringPrinter.cpp */; }; 94FA3DE01405D50400833217 /* ValueObjectConstResultChild.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94FA3DDF1405D50300833217 /* ValueObjectConstResultChild.cpp */; }; @@ -1064,8 +1069,13 @@ dstPath = "$(DEVELOPER_DIR)/usr/share/man/man1/"; dstSubfolderSpec = 0; files = ( + 3FBA69E91B60672A0008F44A /* PythonDataObjects.h in CopyFiles */, AF90106515AB7D3600FF120D /* lldb.1 in CopyFiles */, + 3FBA69E71B60672A0008F44A /* lldb-python.h in CopyFiles */, + 3FBA69DF1B6067020008F44A /* ScriptInterpreterNone.cpp in CopyFiles */, + 3FBA69E01B6067020008F44A /* ScriptInterpreterNone.h in CopyFiles */, 33E5E8461A6736D30024ED68 /* StringConvert.h in CopyFiles */, + 3FBA69EB1B60672A0008F44A /* ScriptInterpreterPython.h in CopyFiles */, AFC234081AF85CE000CDE8B6 /* CommandObjectLanguage.cpp in CopyFiles */, 33E5E8421A672A240024ED68 /* StringConvert.cpp in CopyFiles */, ); @@ -1864,7 +1874,6 @@ 26BC7DE310F1B7F900F91463 /* CommandObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObject.h; path = include/lldb/Interpreter/CommandObject.h; sourceTree = ""; }; 26BC7DE410F1B7F900F91463 /* CommandReturnObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandReturnObject.h; path = include/lldb/Interpreter/CommandReturnObject.h; sourceTree = ""; }; 26BC7DE510F1B7F900F91463 /* ScriptInterpreter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScriptInterpreter.h; path = include/lldb/Interpreter/ScriptInterpreter.h; sourceTree = ""; }; - 26BC7DE610F1B7F900F91463 /* ScriptInterpreterPython.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScriptInterpreterPython.h; path = include/lldb/Interpreter/ScriptInterpreterPython.h; sourceTree = ""; }; 26BC7DF110F1B81A00F91463 /* DynamicLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DynamicLoader.h; path = include/lldb/Target/DynamicLoader.h; sourceTree = ""; }; 26BC7DF210F1B81A00F91463 /* ExecutionContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExecutionContext.h; path = include/lldb/Target/ExecutionContext.h; sourceTree = ""; }; 26BC7DF310F1B81A00F91463 /* Process.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Process.h; path = include/lldb/Target/Process.h; sourceTree = ""; }; @@ -1968,7 +1977,6 @@ 26BC7F0810F1B8DD00F91463 /* CommandInterpreter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandInterpreter.cpp; path = source/Interpreter/CommandInterpreter.cpp; sourceTree = ""; }; 26BC7F0910F1B8DD00F91463 /* CommandObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObject.cpp; path = source/Interpreter/CommandObject.cpp; sourceTree = ""; }; 26BC7F0A10F1B8DD00F91463 /* CommandReturnObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandReturnObject.cpp; path = source/Interpreter/CommandReturnObject.cpp; sourceTree = ""; }; - 26BC7F0C10F1B8DD00F91463 /* ScriptInterpreterPython.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ScriptInterpreterPython.cpp; path = source/Interpreter/ScriptInterpreterPython.cpp; sourceTree = ""; }; 26BC7F1310F1B8EC00F91463 /* Block.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Block.cpp; path = source/Symbol/Block.cpp; sourceTree = ""; }; 26BC7F1410F1B8EC00F91463 /* ClangASTContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangASTContext.cpp; path = source/Symbol/ClangASTContext.cpp; sourceTree = ""; }; 26BC7F1510F1B8EC00F91463 /* CompileUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CompileUnit.cpp; path = source/Symbol/CompileUnit.cpp; sourceTree = ""; }; @@ -2141,6 +2149,13 @@ 3F8169341ABB7A80001DA9DF /* SystemInitializer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SystemInitializer.h; path = include/lldb/Initialization/SystemInitializer.h; sourceTree = ""; }; 3F8169351ABB7A80001DA9DF /* SystemInitializerCommon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SystemInitializerCommon.h; path = include/lldb/Initialization/SystemInitializerCommon.h; sourceTree = ""; }; 3F8169361ABB7A80001DA9DF /* SystemLifetimeManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SystemLifetimeManager.h; path = include/lldb/Initialization/SystemLifetimeManager.h; sourceTree = ""; }; + 3FBA69DD1B6067020008F44A /* ScriptInterpreterNone.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ScriptInterpreterNone.cpp; path = ScriptInterpreter/None/ScriptInterpreterNone.cpp; sourceTree = ""; }; + 3FBA69DE1B6067020008F44A /* ScriptInterpreterNone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScriptInterpreterNone.h; path = ScriptInterpreter/None/ScriptInterpreterNone.h; sourceTree = ""; }; + 3FBA69E21B60672A0008F44A /* lldb-python.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "lldb-python.h"; path = "ScriptInterpreter/Python/lldb-python.h"; sourceTree = ""; }; + 3FBA69E31B60672A0008F44A /* PythonDataObjects.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PythonDataObjects.cpp; path = ScriptInterpreter/Python/PythonDataObjects.cpp; sourceTree = ""; }; + 3FBA69E41B60672A0008F44A /* PythonDataObjects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PythonDataObjects.h; path = ScriptInterpreter/Python/PythonDataObjects.h; sourceTree = ""; }; + 3FBA69E51B60672A0008F44A /* ScriptInterpreterPython.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ScriptInterpreterPython.cpp; path = ScriptInterpreter/Python/ScriptInterpreterPython.cpp; sourceTree = ""; }; + 3FBA69E61B60672A0008F44A /* ScriptInterpreterPython.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScriptInterpreterPython.h; path = ScriptInterpreter/Python/ScriptInterpreterPython.h; sourceTree = ""; }; 3FDFD6C3199C396E009756A7 /* FileAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FileAction.h; path = include/lldb/Target/FileAction.h; sourceTree = ""; }; 3FDFDDBC199C3A06009756A7 /* FileAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FileAction.cpp; path = source/Target/FileAction.cpp; sourceTree = ""; }; 3FDFDDBE199D345E009756A7 /* FileCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FileCache.cpp; path = source/Host/common/FileCache.cpp; sourceTree = ""; }; @@ -2480,8 +2495,6 @@ 94D6A0A916CEB55F00833B6E /* NSSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NSSet.cpp; path = source/DataFormatters/NSSet.cpp; sourceTree = ""; }; 94E367CC140C4EC4001C7A5A /* modify-python-lldb.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = "modify-python-lldb.py"; sourceTree = ""; }; 94E367CE140C4EEA001C7A5A /* python-typemaps.swig */ = {isa = PBXFileReference; lastKnownFileType = text; path = "python-typemaps.swig"; sourceTree = ""; }; - 94EA1D5A15E6C99B00D4171A /* PythonDataObjects.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PythonDataObjects.h; path = include/lldb/Interpreter/PythonDataObjects.h; sourceTree = ""; }; - 94EA1D5B15E6C9B400D4171A /* PythonDataObjects.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PythonDataObjects.cpp; path = source/Interpreter/PythonDataObjects.cpp; sourceTree = ""; }; 94EA27CD17DE91750070F505 /* LibCxxUnorderedMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LibCxxUnorderedMap.cpp; path = source/DataFormatters/LibCxxUnorderedMap.cpp; sourceTree = ""; }; 94EBAC8313D9EE26009BA64E /* PythonPointer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PythonPointer.h; path = include/lldb/Utility/PythonPointer.h; sourceTree = ""; }; 94ED54A119C8A822007BE2EA /* ThreadSafeDenseMap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ThreadSafeDenseMap.h; path = include/lldb/Core/ThreadSafeDenseMap.h; sourceTree = ""; }; @@ -2506,8 +2519,6 @@ 9A22A15E135E30370024DDC3 /* EmulateInstructionARM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EmulateInstructionARM.h; sourceTree = ""; }; 9A22A15F135E30370024DDC3 /* EmulationStateARM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EmulationStateARM.cpp; sourceTree = ""; }; 9A22A160135E30370024DDC3 /* EmulationStateARM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EmulationStateARM.h; sourceTree = ""; }; - 9A2771FB1135A35C00E6ADB6 /* ScriptInterpreterNone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScriptInterpreterNone.h; path = include/lldb/Interpreter/ScriptInterpreterNone.h; sourceTree = ""; }; - 9A2771FC1135A37500E6ADB6 /* ScriptInterpreterNone.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ScriptInterpreterNone.cpp; path = source/Interpreter/ScriptInterpreterNone.cpp; sourceTree = ""; }; 9A357582116CFDEE00E8ED2F /* SBValueList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBValueList.h; path = include/lldb/API/SBValueList.h; sourceTree = ""; }; 9A35758D116CFE0F00E8ED2F /* SBValueList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBValueList.cpp; path = source/API/SBValueList.cpp; sourceTree = ""; }; 9A35765E116E76A700E8ED2F /* StringList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StringList.h; path = include/lldb/Core/StringList.h; sourceTree = ""; }; @@ -2937,6 +2948,7 @@ 266DFE9013FD64D200D0C574 /* OperatingSystem */, 26C5577E132575B6008FD8FE /* Platform */, 260C898A10F57C5600BB2B04 /* Process */, + 3FBA69DA1B6066D20008F44A /* ScriptInterpreter */, AF11CB34182CA85A00D9B618 /* SystemRuntime */, 260C89B110F57C5600BB2B04 /* SymbolFile */, 260C89E010F57C5600BB2B04 /* SymbolVendor */, @@ -4509,14 +4521,8 @@ B2462246141AD37D00F3D409 /* OptionGroupWatchpoint.cpp */, 26ACEC2715E077AE00E94760 /* Property.h */, 2640E19E15DC78FD00F23B50 /* Property.cpp */, - 94EA1D5A15E6C99B00D4171A /* PythonDataObjects.h */, - 94EA1D5B15E6C9B400D4171A /* PythonDataObjects.cpp */, 26BC7DE510F1B7F900F91463 /* ScriptInterpreter.h */, 9A82010B10FFB49800182560 /* ScriptInterpreter.cpp */, - 9A2771FB1135A35C00E6ADB6 /* ScriptInterpreterNone.h */, - 9A2771FC1135A37500E6ADB6 /* ScriptInterpreterNone.cpp */, - 26BC7DE610F1B7F900F91463 /* ScriptInterpreterPython.h */, - 26BC7F0C10F1B8DD00F91463 /* ScriptInterpreterPython.cpp */, ); name = Interpreter; sourceTree = ""; @@ -4898,6 +4904,36 @@ name = Initialization; sourceTree = ""; }; + 3FBA69DA1B6066D20008F44A /* ScriptInterpreter */ = { + isa = PBXGroup; + children = ( + 3FBA69DC1B6066E90008F44A /* None */, + 3FBA69DB1B6066E40008F44A /* Python */, + ); + name = ScriptInterpreter; + sourceTree = ""; + }; + 3FBA69DB1B6066E40008F44A /* Python */ = { + isa = PBXGroup; + children = ( + 3FBA69E21B60672A0008F44A /* lldb-python.h */, + 3FBA69E31B60672A0008F44A /* PythonDataObjects.cpp */, + 3FBA69E41B60672A0008F44A /* PythonDataObjects.h */, + 3FBA69E51B60672A0008F44A /* ScriptInterpreterPython.cpp */, + 3FBA69E61B60672A0008F44A /* ScriptInterpreterPython.h */, + ); + name = Python; + sourceTree = ""; + }; + 3FBA69DC1B6066E90008F44A /* None */ = { + isa = PBXGroup; + children = ( + 3FBA69DD1B6067020008F44A /* ScriptInterpreterNone.cpp */, + 3FBA69DE1B6067020008F44A /* ScriptInterpreterNone.h */, + ); + name = None; + sourceTree = ""; + }; 3FDFDDC4199D37BE009756A7 /* posix */ = { isa = PBXGroup; children = ( @@ -6157,8 +6193,6 @@ 26474CBE18D0CB2D0073DEBA /* RegisterContextMach_i386.cpp in Sources */, 2689008613353E2200698AC0 /* Options.cpp in Sources */, 2689008713353E2200698AC0 /* ScriptInterpreter.cpp in Sources */, - 2689008813353E2200698AC0 /* ScriptInterpreterNone.cpp in Sources */, - 2689008913353E2200698AC0 /* ScriptInterpreterPython.cpp in Sources */, 260A63191861009E00FECF8E /* IOHandler.cpp in Sources */, 2689008D13353E4200698AC0 /* DynamicLoaderMacOSXDYLD.cpp in Sources */, 2689008E13353E4200698AC0 /* DynamicLoaderStatic.cpp in Sources */, @@ -6338,6 +6372,7 @@ 26A7A035135E6E4200FB369E /* OptionValue.cpp in Sources */, 9A22A161135E30370024DDC3 /* EmulateInstructionARM.cpp in Sources */, AFDFDFD119E34D3400EAE509 /* ConnectionFileDescriptorPosix.cpp in Sources */, + 3FBA69ED1B60674B0008F44A /* ScriptInterpreterPython.cpp in Sources */, 9A22A163135E30370024DDC3 /* EmulationStateARM.cpp in Sources */, 9A4F35101368A51A00823F52 /* StreamAsynchronousIO.cpp in Sources */, AF1D88691B575E8D003CB899 /* ValueObjectConstResultCast.cpp in Sources */, @@ -6401,10 +6436,12 @@ 94B6E76213D88365005F417F /* ValueObjectSyntheticFilter.cpp in Sources */, 267A47FF1B1411D90021A5BC /* NativeWatchpointList.cpp in Sources */, 26F4A21C13FBA31A0064B613 /* ThreadMemory.cpp in Sources */, + 3FBA69E11B6067120008F44A /* ScriptInterpreterNone.cpp in Sources */, 94EA27CE17DE91750070F505 /* LibCxxUnorderedMap.cpp in Sources */, 266DFE9713FD656E00D0C574 /* OperatingSystem.cpp in Sources */, 26954EBE1401EE8B00294D09 /* DynamicRegisterInfo.cpp in Sources */, 255EFF761AFABA950069F277 /* LockFilePosix.cpp in Sources */, + 3FBA69EC1B6067430008F44A /* PythonDataObjects.cpp in Sources */, 26274FA714030F79006BA130 /* DynamicLoaderDarwinKernel.cpp in Sources */, 94FA3DE01405D50400833217 /* ValueObjectConstResultChild.cpp in Sources */, 3FDFED2819BA6D96009756A7 /* HostThread.cpp in Sources */, @@ -6466,7 +6503,6 @@ 26491E3E15E1DB9F00CBFFC2 /* OptionValueRegex.cpp in Sources */, 2697A39315E404B1003E682C /* OptionValueArch.cpp in Sources */, 6D55B2921A8A806200A70529 /* GDBRemoteCommunicationServerPlatform.cpp in Sources */, - 94EA1D5C15E6C9B400D4171A /* PythonDataObjects.cpp in Sources */, 94D6A0AC16CEB55F00833B6E /* NSSet.cpp in Sources */, 94CD704E16F8DDEA00CF1E42 /* Cocoa.cpp in Sources */, 2698699B15E6CBD0002415FF /* OperatingSystemPython.cpp in Sources */, Index: source/API/CMakeLists.txt =================================================================== --- source/API/CMakeLists.txt +++ source/API/CMakeLists.txt @@ -72,6 +72,13 @@ ${LLDB_VERS_GENERATED_FILE} ) +# This should not be part of LLDBDependencies.cmake, because we don't +# want every single library taking a dependency on the script interpreters. +target_link_libraries(liblldb PRIVATE + lldbPluginScriptInterpreterNone + lldbPluginScriptInterpreterPython + ) + set_target_properties(liblldb PROPERTIES VERSION ${LLDB_VERSION} Index: source/API/SBCommandInterpreter.cpp =================================================================== --- source/API/SBCommandInterpreter.cpp +++ source/API/SBCommandInterpreter.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "lldb/lldb-types.h" + #include "lldb/Core/SourceManager.h" #include "lldb/Core/Listener.h" #include "lldb/Interpreter/CommandInterpreter.h" Index: source/API/SystemInitializerFull.cpp =================================================================== --- source/API/SystemInitializerFull.cpp +++ source/API/SystemInitializerFull.cpp @@ -7,12 +7,23 @@ // //===----------------------------------------------------------------------===// +#if !defined(LLDB_DISABLE_PYTHON) +#include "Plugins/ScriptInterpreter/Python/lldb-python.h" +#endif + #include "lldb/API/SystemInitializerFull.h" +#include "lldb/API/SBCommandInterpreter.h" + +#if !defined(LLDB_DISABLE_PYTHON) +#include "Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h" +#endif + #include "lldb/Core/Debugger.h" #include "lldb/Core/Timer.h" #include "lldb/Host/Host.h" #include "lldb/Initialization/SystemInitializerCommon.h" +#include "lldb/Interpreter/CommandInterpreter.h" #include "Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h" #include "Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h" @@ -38,6 +49,7 @@ #include "Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h" #include "Plugins/Process/elf-core/ProcessElfCore.h" #include "Plugins/Process/gdb-remote/ProcessGDBRemote.h" +#include "Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h" #include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h" @@ -61,10 +73,6 @@ #include "Plugins/Process/Windows/ProcessWindows.h" #endif -#if !defined(LLDB_DISABLE_PYTHON) -#include "lldb/Interpreter/ScriptInterpreterPython.h" -#endif - #include "llvm/Support/TargetSelect.h" #include @@ -221,9 +229,17 @@ void SystemInitializerFull::Initialize() { + SystemInitializerCommon::Initialize(); + +#if !defined(LLDB_DISABLE_PYTHON) InitializeSWIG(); - SystemInitializerCommon::Initialize(); + // ScriptInterpreterPython::Initialize() depends on things like HostInfo being initialized + // so it can compute the python directory etc, so we need to do this after + // SystemInitializerCommon::Initialize(). + ScriptInterpreterNone::Initialize(); + ScriptInterpreterPython::Initialize(); +#endif // Initialize LLVM and Clang llvm::InitializeAllTargets(); @@ -380,8 +396,3 @@ // Now shutdown the common parts, in reverse order. SystemInitializerCommon::Terminate(); } - -void SystemInitializerFull::TerminateSWIG() -{ - -} Index: source/Core/PluginManager.cpp =================================================================== --- source/Core/PluginManager.cpp +++ source/Core/PluginManager.cpp @@ -1764,6 +1764,110 @@ return NULL; } +#pragma mark ScriptInterpreter + +struct ScriptInterpreterInstance +{ + ScriptInterpreterInstance() + : name() + , language(lldb::eScriptLanguageNone) + , description() + , create_callback(NULL) + { + } + + ConstString name; + lldb::ScriptLanguage language; + std::string description; + ScriptInterpreterCreateInstance create_callback; +}; + +typedef std::vector ScriptInterpreterInstances; + +static Mutex & +GetScriptInterpreterMutex() +{ + static Mutex g_instances_mutex(Mutex::eMutexTypeRecursive); + return g_instances_mutex; +} + +static ScriptInterpreterInstances & +GetScriptInterpreterInstances() +{ + static ScriptInterpreterInstances g_instances; + return g_instances; +} + +bool +PluginManager::RegisterPlugin(const ConstString &name, const char *description, lldb::ScriptLanguage script_language, + ScriptInterpreterCreateInstance create_callback) +{ + if (!create_callback) + return false; + ScriptInterpreterInstance instance; + assert((bool)name); + instance.name = name; + if (description && description[0]) + instance.description = description; + instance.create_callback = create_callback; + instance.language = script_language; + Mutex::Locker locker(GetScriptInterpreterMutex()); + GetScriptInterpreterInstances().push_back(instance); + return false; +} + +bool +PluginManager::UnregisterPlugin(ScriptInterpreterCreateInstance create_callback) +{ + if (!create_callback) + return false; + Mutex::Locker locker(GetScriptInterpreterMutex()); + ScriptInterpreterInstances &instances = GetScriptInterpreterInstances(); + + ScriptInterpreterInstances::iterator pos, end = instances.end(); + for (pos = instances.begin(); pos != end; ++pos) + { + if (pos->create_callback != create_callback) + continue; + + instances.erase(pos); + return true; + } + return false; +} + +ScriptInterpreterCreateInstance +PluginManager::GetScriptInterpreterCreateCallbackAtIndex(uint32_t idx) +{ + Mutex::Locker locker(GetScriptInterpreterMutex()); + ScriptInterpreterInstances &instances = GetScriptInterpreterInstances(); + if (idx < instances.size()) + return instances[idx].create_callback; + return nullptr; +} + +lldb::ScriptInterpreterSP +PluginManager::GetScriptInterpreterForLanguage(lldb::ScriptLanguage script_lang, CommandInterpreter &interpreter) +{ + Mutex::Locker locker(GetScriptInterpreterMutex()); + ScriptInterpreterInstances &instances = GetScriptInterpreterInstances(); + + ScriptInterpreterInstances::iterator pos, end = instances.end(); + ScriptInterpreterCreateInstance none_instance = nullptr; + for (pos = instances.begin(); pos != end; ++pos) + { + if (pos->language == lldb::eScriptLanguageNone) + none_instance = pos->create_callback; + + if (script_lang == pos->language) + return pos->create_callback(interpreter); + } + + // If we didn't find one, return the ScriptInterpreter for the null language. + assert(none_instance != nullptr); + return none_instance(interpreter); +} + #pragma mark SymbolFile struct SymbolFileInstance Index: source/Host/macosx/HostInfoMacOSX.mm =================================================================== --- source/Host/macosx/HostInfoMacOSX.mm +++ source/Host/macosx/HostInfoMacOSX.mm @@ -7,7 +7,9 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" +#if !defined(LLDB_DISABLE_PYTHON) +#include "Plugins/ScriptInterpreter/Python/lldb-python.h" +#endif #include "lldb/Host/HostInfo.h" #include "lldb/Host/macosx/HostInfoMacOSX.h" Index: source/Host/posix/HostInfoPosix.cpp =================================================================== --- source/Host/posix/HostInfoPosix.cpp +++ source/Host/posix/HostInfoPosix.cpp @@ -7,7 +7,10 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" +#if !defined(LLDB_DISABLE_PYTHON) +#include "Plugins/ScriptInterpreter/Python/lldb-python.h" +#endif + #include "lldb/Core/Log.h" #include "lldb/Host/posix/HostInfoPosix.h" Index: source/Initialization/SystemInitializerCommon.cpp =================================================================== --- source/Initialization/SystemInitializerCommon.cpp +++ source/Initialization/SystemInitializerCommon.cpp @@ -13,7 +13,6 @@ #include "lldb/Host/HostInfo.h" #include "lldb/Core/Log.h" #include "lldb/Core/Timer.h" -#include "lldb/Interpreter/ScriptInterpreterPython.h" #include "Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h" #include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h" @@ -141,7 +140,6 @@ ProcessWindowsLog::Initialize(); #endif #ifndef LLDB_DISABLE_PYTHON - ScriptInterpreterPython::InitializePrivate(); OperatingSystemPython::Initialize(); #endif } Index: source/Interpreter/CMakeLists.txt =================================================================== --- source/Interpreter/CMakeLists.txt +++ source/Interpreter/CMakeLists.txt @@ -43,8 +43,5 @@ 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 @@ -41,9 +41,9 @@ #include "../Commands/CommandObjectWatchpoint.h" #include "../Commands/CommandObjectLanguage.h" - #include "lldb/Core/Debugger.h" #include "lldb/Core/Log.h" +#include "lldb/Core/PluginManager.h" #include "lldb/Core/State.h" #include "lldb/Core/Stream.h" #include "lldb/Core/StreamFile.h" @@ -62,8 +62,6 @@ #include "lldb/Interpreter/Options.h" #include "lldb/Interpreter/OptionValueProperties.h" #include "lldb/Interpreter/Property.h" -#include "lldb/Interpreter/ScriptInterpreterNone.h" -#include "lldb/Interpreter/ScriptInterpreterPython.h" #include "lldb/Target/Process.h" @@ -104,28 +102,23 @@ return class_name; } -CommandInterpreter::CommandInterpreter -( - Debugger &debugger, - ScriptLanguage script_language, - bool synchronous_execution -) : - Broadcaster (&debugger, CommandInterpreter::GetStaticBroadcasterClass().AsCString()), - Properties(OptionValuePropertiesSP(new OptionValueProperties(ConstString("interpreter")))), - IOHandlerDelegate (IOHandlerDelegate::Completion::LLDBCommand), - m_debugger (debugger), - m_synchronous_execution (synchronous_execution), - m_skip_lldbinit_files (false), - m_skip_app_init_files (false), - m_script_interpreter_ap (), - m_command_io_handler_sp (), - m_comment_char ('#'), - m_batch_command_mode (false), - m_truncation_warning(eNoTruncation), - m_command_source_depth (0), - m_num_errors(0), - m_quit_requested(false), - m_stopped_for_crash(false) +CommandInterpreter::CommandInterpreter(Debugger &debugger, ScriptLanguage script_language, bool synchronous_execution) + : Broadcaster(&debugger, CommandInterpreter::GetStaticBroadcasterClass().AsCString()) + , Properties(OptionValuePropertiesSP(new OptionValueProperties(ConstString("interpreter")))) + , IOHandlerDelegate(IOHandlerDelegate::Completion::LLDBCommand) + , m_debugger(debugger) + , m_synchronous_execution(synchronous_execution) + , m_skip_lldbinit_files(false) + , m_skip_app_init_files(false) + , m_script_interpreter_sp() + , m_command_io_handler_sp() + , m_comment_char('#') + , m_batch_command_mode(false) + , m_truncation_warning(eNoTruncation) + , m_command_source_depth(0) + , m_num_errors(0) + , m_quit_requested(false) + , m_stopped_for_crash(false) { debugger.SetScriptLanguage (script_language); @@ -392,9 +385,9 @@ CommandInterpreter::Clear() { m_command_io_handler_sp.reset(); - - if (m_script_interpreter_ap) - m_script_interpreter_ap->Clear(); + + if (m_script_interpreter_sp) + m_script_interpreter_sp->Clear(); } const char * @@ -2708,48 +2701,19 @@ } ScriptInterpreter * -CommandInterpreter::GetScriptInterpreter (bool can_create) +CommandInterpreter::GetScriptInterpreter(bool can_create) { - if (m_script_interpreter_ap.get() != nullptr) - return m_script_interpreter_ap.get(); - + if (m_script_interpreter_sp) + return m_script_interpreter_sp.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(); + m_script_interpreter_sp = PluginManager::GetScriptInterpreterForLanguage(script_lang, *this); + return m_script_interpreter_sp.get(); } - - bool CommandInterpreter::GetSynchronous () { Index: source/Interpreter/PythonDataObjects.cpp =================================================================== --- source/Interpreter/PythonDataObjects.cpp +++ /dev/null @@ -1,524 +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" -#include "lldb/Interpreter/ScriptInterpreterPython.h" - -using namespace lldb_private; -using namespace lldb; - -void -StructuredPythonObject::Dump(Stream &s) const -{ - s << "Python Obj: 0x" << GetValue(); -} - -//---------------------------------------------------------------------- -// PythonObject -//---------------------------------------------------------------------- - -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"); -} - -PyObjectType -PythonObject::GetObjectType() const -{ - if (IsNULLOrNone()) - return PyObjectType::None; - - if (PyList_Check(m_py_obj)) - return PyObjectType::List; - if (PyDict_Check(m_py_obj)) - return PyObjectType::Dictionary; - if (PyString_Check(m_py_obj)) - return PyObjectType::String; - if (PyInt_Check(m_py_obj) || PyLong_Check(m_py_obj)) - return PyObjectType::Integer; - return PyObjectType::Unknown; -} - -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)); -} - -StructuredData::ObjectSP -PythonObject::CreateStructuredObject() const -{ - switch (GetObjectType()) - { - case PyObjectType::Dictionary: - return PythonDictionary(m_py_obj).CreateStructuredDictionary(); - case PyObjectType::Integer: - return PythonInteger(m_py_obj).CreateStructuredInteger(); - case PyObjectType::List: - return PythonList(m_py_obj).CreateStructuredArray(); - case PyObjectType::String: - return PythonString(m_py_obj).CreateStructuredString(); - case PyObjectType::None: - return StructuredData::ObjectSP(); - default: - return StructuredData::ObjectSP(new StructuredPythonObject(m_py_obj)); - } -} - -//---------------------------------------------------------------------- -// 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 (llvm::StringRef string) : - PythonObject(PyString_FromStringAndSize(string.data(), string.size())) -{ -} - -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; -} - -llvm::StringRef -PythonString::GetString() const -{ - if (m_py_obj) - return llvm::StringRef(PyString_AsString(m_py_obj), GetSize()); - return llvm::StringRef(); -} - -size_t -PythonString::GetSize() const -{ - if (m_py_obj) - return PyString_Size(m_py_obj); - return 0; -} - -void -PythonString::SetString (llvm::StringRef string) -{ - PythonObject::Reset(PyString_FromStringAndSize(string.data(), string.size())); -} - -StructuredData::StringSP -PythonString::CreateStructuredString() const -{ - StructuredData::StringSP result(new StructuredData::String); - result->SetValue(GetString()); - return result; -} - -//---------------------------------------------------------------------- -// 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 (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() const -{ - 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)); -} - -StructuredData::IntegerSP -PythonInteger::CreateStructuredInteger() const -{ - StructuredData::IntegerSP result(new StructuredData::Integer); - result->SetValue(GetInteger()); - return result; -} - -//---------------------------------------------------------------------- -// 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 () -{ -} - -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() const -{ - if (m_py_obj) - return PyList_GET_SIZE(m_py_obj); - return 0; -} - -PythonObject -PythonList::GetItemAtIndex(uint32_t index) const -{ - 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()); -} - -StructuredData::ArraySP -PythonList::CreateStructuredArray() const -{ - StructuredData::ArraySP result(new StructuredData::Array); - uint32_t count = GetSize(); - for (uint32_t i = 0; i < count; ++i) - { - PythonObject obj = GetItemAtIndex(i); - result->AddItem(obj.CreateStructuredObject()); - } - return result; -} - -//---------------------------------------------------------------------- -// 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 () -{ -} - -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() const -{ - 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()); -} - -StructuredData::DictionarySP -PythonDictionary::CreateStructuredDictionary() const -{ - StructuredData::DictionarySP result(new StructuredData::Dictionary); - PythonList keys(GetKeys()); - uint32_t num_keys = keys.GetSize(); - for (uint32_t i = 0; i < num_keys; ++i) - { - PythonObject key = keys.GetItemAtIndex(i); - PythonString key_str = key.Str(); - PythonObject value = GetItemForKey(key); - StructuredData::ObjectSP structured_value = value.CreateStructuredObject(); - result->AddItem(key_str.GetString(), structured_value); - } - return result; -} - -#endif Index: source/Interpreter/ScriptInterpreterNone.cpp =================================================================== --- source/Interpreter/ScriptInterpreterNone.cpp +++ /dev/null @@ -1,42 +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/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,3202 +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/Core/ValueObject.h" -#include "lldb/DataFormatters/TypeSummary.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 - -#include "llvm/ADT/StringRef.h" - -using namespace lldb; -using namespace lldb_private; - -static ScriptInterpreterPython::SWIGInitCallback g_swig_init_callback = nullptr; -static ScriptInterpreterPython::SWIGBreakpointCallbackFunction g_swig_breakpoint_callback = nullptr; -static ScriptInterpreterPython::SWIGWatchpointCallbackFunction g_swig_watchpoint_callback = nullptr; -static ScriptInterpreterPython::SWIGPythonTypeScriptCallbackFunction g_swig_typescript_callback = nullptr; -static ScriptInterpreterPython::SWIGPythonCreateSyntheticProvider g_swig_synthetic_script = nullptr; -static ScriptInterpreterPython::SWIGPythonCreateCommandObject g_swig_create_cmd = nullptr; -static ScriptInterpreterPython::SWIGPythonCalculateNumChildren g_swig_calc_children = nullptr; -static ScriptInterpreterPython::SWIGPythonGetChildAtIndex g_swig_get_child_index = nullptr; -static ScriptInterpreterPython::SWIGPythonGetIndexOfChildWithName g_swig_get_index_child = nullptr; -static ScriptInterpreterPython::SWIGPythonCastPyObjectToSBValue g_swig_cast_to_sbvalue = nullptr; -static ScriptInterpreterPython::SWIGPythonGetValueObjectSPFromSBValue g_swig_get_valobj_sp_from_sbvalue = nullptr; -static ScriptInterpreterPython::SWIGPythonUpdateSynthProviderInstance g_swig_update_provider = nullptr; -static ScriptInterpreterPython::SWIGPythonMightHaveChildrenSynthProviderInstance g_swig_mighthavechildren_provider = nullptr; -static ScriptInterpreterPython::SWIGPythonGetValueSynthProviderInstance g_swig_getvalue_provider = nullptr; -static ScriptInterpreterPython::SWIGPythonCallCommand g_swig_call_command = nullptr; -static ScriptInterpreterPython::SWIGPythonCallCommandObject g_swig_call_command_object = nullptr; -static ScriptInterpreterPython::SWIGPythonCallModuleInit g_swig_call_module_init = nullptr; -static ScriptInterpreterPython::SWIGPythonCreateOSPlugin g_swig_create_os_plugin = nullptr; -static ScriptInterpreterPython::SWIGPythonScriptKeyword_Process g_swig_run_script_keyword_process = nullptr; -static ScriptInterpreterPython::SWIGPythonScriptKeyword_Thread g_swig_run_script_keyword_thread = nullptr; -static ScriptInterpreterPython::SWIGPythonScriptKeyword_Target g_swig_run_script_keyword_target = nullptr; -static ScriptInterpreterPython::SWIGPythonScriptKeyword_Frame g_swig_run_script_keyword_frame = nullptr; -static ScriptInterpreterPython::SWIGPythonScriptKeyword_Value g_swig_run_script_keyword_value = nullptr; -static ScriptInterpreterPython::SWIGPython_GetDynamicSetting g_swig_plugin_get = nullptr; -static ScriptInterpreterPython::SWIGPythonCreateScriptedThreadPlan g_swig_thread_plan_script = nullptr; -static ScriptInterpreterPython::SWIGPythonCallThreadPlan g_swig_call_thread_plan = nullptr; - -static bool g_initialized = false; - -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) -{ - assert(g_initialized && "ScriptInterpreterPython created but initialize has not been called!"); - - 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(); - - 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(); - - 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 () -{ - // the session dictionary may hold objects with complex state - // which means that they may need to be torn down with some level of smarts - // and that, in turn, requires a valid thread state - // force Python to procure itself such a thread state, nuke the session dictionary - // and then release it for others to use and proceed with the rest of the shutdown - auto gil_state = PyGILState_Ensure(); - m_session_dict.Reset(); - PyGILState_Release(gil_state); -} - -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; -} - -static PyObject * -PyFile_FromFile_Const(FILE *fp, const char *name, const char *mode, int (*close)(FILE *)) -{ - // Read through the Python source, doesn't seem to modify these strings - return PyFile_FromFile(fp, const_cast(name), const_cast(mode), close); -} - -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_Const (in, "", "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_Const (out, "", "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_Const (err, "", "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) - { - - } - - ~IOHandlerPythonInterpreter() override - { - - } - - ConstString - GetControlSequence (char ch) override - { - if (ch == 'd') - return ConstString("quit()\n"); - return ConstString(); - } - - void - Run () override - { - 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); - } - - void - Cancel () override - { - - } - - bool - Interrupt () override - { - return m_python->Interrupt(); - } - - void - GotEOF() override - { - - } -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; -} - -StructuredData::GenericSP -ScriptInterpreterPython::OSPlugin_CreatePluginObject(const char *class_name, lldb::ProcessSP process_sp) -{ - if (class_name == nullptr || class_name[0] == '\0') - return StructuredData::GenericSP(); - - if (!process_sp) - return StructuredData::GenericSP(); - - 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 StructuredData::GenericSP(new StructuredPythonObject(ret_val)); -} - -StructuredData::DictionarySP -ScriptInterpreterPython::OSPlugin_RegisterInfo(StructuredData::ObjectSP 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 StructuredData::DictionarySP(); - - StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric(); - if (!generic) - return nullptr; - - PyObject *implementor = (PyObject *)generic->GetValue(); - - if (implementor == nullptr || implementor == Py_None) - return StructuredData::DictionarySP(); - - PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); - - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - if (pmeth == nullptr || pmeth == Py_None) - { - Py_XDECREF(pmeth); - return StructuredData::DictionarySP(); - } - - if (PyCallable_Check(pmeth) == 0) - { - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - Py_XDECREF(pmeth); - return StructuredData::DictionarySP(); - } - - 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(); - } - - PythonDictionary result_dict(py_return); - return result_dict.CreateStructuredDictionary(); -} - -StructuredData::ArraySP -ScriptInterpreterPython::OSPlugin_ThreadsInfo(StructuredData::ObjectSP 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 StructuredData::ArraySP(); - - StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric(); - if (!generic) - return nullptr; - PyObject *implementor = (PyObject *)generic->GetValue(); - - if (implementor == nullptr || implementor == Py_None) - return StructuredData::ArraySP(); - - PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); - - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - if (pmeth == nullptr || pmeth == Py_None) - { - Py_XDECREF(pmeth); - return StructuredData::ArraySP(); - } - - if (PyCallable_Check(pmeth) == 0) - { - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - Py_XDECREF(pmeth); - return StructuredData::ArraySP(); - } - - 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(); - } - - PythonList ResultList(py_return); - return ResultList.CreateStructuredArray(); -} - -// 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"; } - -StructuredData::StringSP -ScriptInterpreterPython::OSPlugin_RegisterContextData(StructuredData::ObjectSP 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 StructuredData::StringSP(); - - StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric(); - if (!generic) - return nullptr; - PyObject *implementor = (PyObject *)generic->GetValue(); - - if (implementor == nullptr || implementor == Py_None) - return StructuredData::StringSP(); - - PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); - - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - if (pmeth == nullptr || pmeth == Py_None) - { - Py_XDECREF(pmeth); - return StructuredData::StringSP(); - } - - if (PyCallable_Check(pmeth) == 0) - { - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - Py_XDECREF(pmeth); - return StructuredData::StringSP(); - } - - 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(); - } - PythonString result_string(py_return); - return result_string.CreateStructuredString(); -} - -StructuredData::DictionarySP -ScriptInterpreterPython::OSPlugin_CreateThread(StructuredData::ObjectSP 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 StructuredData::DictionarySP(); - - StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric(); - if (!generic) - return nullptr; - PyObject *implementor = (PyObject *)generic->GetValue(); - - if (implementor == nullptr || implementor == Py_None) - return StructuredData::DictionarySP(); - - PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); - - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - if (pmeth == nullptr || pmeth == Py_None) - { - Py_XDECREF(pmeth); - return StructuredData::DictionarySP(); - } - - if (PyCallable_Check(pmeth) == 0) - { - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - Py_XDECREF(pmeth); - return StructuredData::DictionarySP(); - } - - 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(); - } - - PythonDictionary result_dict(py_return); - return result_dict.CreateStructuredDictionary(); -} - -StructuredData::ObjectSP -ScriptInterpreterPython::CreateScriptedThreadPlan(const char *class_name, lldb::ThreadPlanSP thread_plan_sp) -{ - if (class_name == nullptr || class_name[0] == '\0') - return StructuredData::ObjectSP(); - - if (!thread_plan_sp.get()) - return StructuredData::ObjectSP(); - - Debugger &debugger = thread_plan_sp->GetTarget().GetDebugger(); - ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter(); - ScriptInterpreterPython *python_interpreter = static_cast(script_interpreter); - - if (!script_interpreter) - return StructuredData::ObjectSP(); - - 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 StructuredData::ObjectSP(new StructuredPythonObject(ret_val)); -} - -bool -ScriptInterpreterPython::ScriptedThreadPlanExplainsStop(StructuredData::ObjectSP implementor_sp, Event *event, bool &script_error) -{ - bool explains_stop = true; - StructuredData::Generic *generic = nullptr; - if (implementor_sp) - generic = implementor_sp->GetAsGeneric(); - if (generic) - { - Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - explains_stop = g_swig_call_thread_plan(generic->GetValue(), "explains_stop", event, script_error); - if (script_error) - return true; - } - return explains_stop; -} - -bool -ScriptInterpreterPython::ScriptedThreadPlanShouldStop(StructuredData::ObjectSP implementor_sp, Event *event, bool &script_error) -{ - bool should_stop = true; - StructuredData::Generic *generic = nullptr; - if (implementor_sp) - generic = implementor_sp->GetAsGeneric(); - if (generic) - { - Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - should_stop = g_swig_call_thread_plan(generic->GetValue(), "should_stop", event, script_error); - if (script_error) - return true; - } - return should_stop; -} - -lldb::StateType -ScriptInterpreterPython::ScriptedThreadPlanGetRunState(StructuredData::ObjectSP implementor_sp, bool &script_error) -{ - bool should_step = false; - StructuredData::Generic *generic = nullptr; - if (implementor_sp) - generic = implementor_sp->GetAsGeneric(); - if (generic) - { - Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - should_step = g_swig_call_thread_plan(generic->GetValue(), "should_step", NULL, script_error); - if (script_error) - should_step = true; - } - if (should_step) - return lldb::eStateStepping; - else - return lldb::eStateRunning; -} - -StructuredData::ObjectSP -ScriptInterpreterPython::LoadPluginModule(const FileSpec &file_spec, lldb_private::Error &error) -{ - if (!file_spec.Exists()) - { - error.SetErrorString("no such file"); - return StructuredData::ObjectSP(); - } - - StructuredData::ObjectSP module_sp; - - if (LoadScriptingModule(file_spec.GetPath().c_str(),true,true,error,&module_sp)) - return module_sp; - - return StructuredData::ObjectSP(); -} - -StructuredData::DictionarySP -ScriptInterpreterPython::GetDynamicSettings(StructuredData::ObjectSP plugin_module_sp, Target *target, const char *setting_name, - lldb_private::Error &error) -{ - if (!plugin_module_sp || !target || !setting_name || !setting_name[0] || !g_swig_plugin_get) - return StructuredData::DictionarySP(); - StructuredData::Generic *generic = plugin_module_sp->GetAsGeneric(); - if (!generic) - return StructuredData::DictionarySP(); - - 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(generic->GetValue(), setting_name, target_sp); - } - - PythonDictionary py_dict(reply_pyobj); - - return py_dict.CreateStructuredDictionary(); -} - -StructuredData::ObjectSP -ScriptInterpreterPython::CreateSyntheticScriptedProvider(const char *class_name, lldb::ValueObjectSP valobj) -{ - if (class_name == nullptr || class_name[0] == '\0') - return StructuredData::ObjectSP(); - - if (!valobj.get()) - return StructuredData::ObjectSP(); - - ExecutionContext exe_ctx (valobj->GetExecutionContextRef()); - Target *target = exe_ctx.GetTargetPtr(); - - if (!target) - return StructuredData::ObjectSP(); - - Debugger &debugger = target->GetDebugger(); - ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter(); - ScriptInterpreterPython *python_interpreter = (ScriptInterpreterPython *) script_interpreter; - - if (!script_interpreter) - return StructuredData::ObjectSP(); - - void *ret_val = nullptr; - - { - 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 StructuredData::ObjectSP(new StructuredPythonObject(ret_val)); -} - -StructuredData::GenericSP -ScriptInterpreterPython::CreateScriptCommandObject (const char *class_name) -{ - DebuggerSP debugger_sp(GetCommandInterpreter().GetDebugger().shared_from_this()); - - if (class_name == nullptr || class_name[0] == '\0') - return StructuredData::GenericSP(); - - if (!debugger_sp.get()) - return StructuredData::GenericSP(); - - void* ret_val; - - { - Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - ret_val = g_swig_create_cmd (class_name, - m_dictionary_name.c_str(), - debugger_sp); - } - - return StructuredData::GenericSP(new StructuredPythonObject(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, - StructuredData::ObjectSP &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 = nullptr; - StructuredData::Generic *generic = nullptr; - if (callee_wrapper_sp) - { - generic = callee_wrapper_sp->GetAsGeneric(); - if (generic) - old_callee = generic->GetValue(); - } - 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.reset(new StructuredPythonObject(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 StructuredData::ObjectSP &implementor_sp) -{ - if (!implementor_sp) - return 0; - StructuredData::Generic *generic = implementor_sp->GetAsGeneric(); - if (!generic) - return 0; - void *implementor = generic->GetValue(); - if (!implementor) - return 0; - - if (!g_swig_calc_children) - return 0; - - size_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 StructuredData::ObjectSP &implementor_sp, uint32_t idx) -{ - if (!implementor_sp) - return lldb::ValueObjectSP(); - - StructuredData::Generic *generic = implementor_sp->GetAsGeneric(); - if (!generic) - return lldb::ValueObjectSP(); - void *implementor = generic->GetValue(); - 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 StructuredData::ObjectSP &implementor_sp, const char *child_name) -{ - if (!implementor_sp) - return UINT32_MAX; - - StructuredData::Generic *generic = implementor_sp->GetAsGeneric(); - if (!generic) - return UINT32_MAX; - void *implementor = generic->GetValue(); - 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 StructuredData::ObjectSP &implementor_sp) -{ - bool ret_val = false; - - if (!implementor_sp) - return ret_val; - - StructuredData::Generic *generic = implementor_sp->GetAsGeneric(); - if (!generic) - return ret_val; - void *implementor = generic->GetValue(); - 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 StructuredData::ObjectSP &implementor_sp) -{ - bool ret_val = false; - - if (!implementor_sp) - return ret_val; - - StructuredData::Generic *generic = implementor_sp->GetAsGeneric(); - if (!generic) - return ret_val; - void *implementor = generic->GetValue(); - 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 StructuredData::ObjectSP &implementor_sp) -{ - lldb::ValueObjectSP ret_val(nullptr); - - if (!implementor_sp) - return ret_val; - - StructuredData::Generic *generic = implementor_sp->GetAsGeneric(); - if (!generic) - return ret_val; - void *implementor = generic->GetValue(); - 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, - StructuredData::ObjectSP *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->reset(new StructuredPythonObject(module_pyobj)); - } - - return true; - } -} - -bool -ScriptInterpreterPython::IsReservedWord (const char* word) -{ - if (!word || !word[0]) - return false; - - llvm::StringRef word_sr(word); - - // filter out a few characters that would just confuse us - // and that are clearly not keyword material anyway - if (word_sr.find_first_of("'\"") != llvm::StringRef::npos) - return false; - - 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; -} - -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; -} - -bool -ScriptInterpreterPython::RunScriptBasedCommand (StructuredData::GenericSP impl_obj_sp, - const char* args, - ScriptedCommandSynchronicity synchronicity, - lldb_private::CommandReturnObject& cmd_retobj, - Error& error, - const lldb_private::ExecutionContext& exe_ctx) -{ - if (!impl_obj_sp || !impl_obj_sp->IsValid()) - { - error.SetErrorString("no function to execute"); - return false; - } - - if (!g_swig_call_command_object) - { - 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_object (impl_obj_sp->GetValue(), - 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; - } -} - -bool -ScriptInterpreterPython::GetShortHelpForCommandObject (StructuredData::GenericSP cmd_obj_sp, - std::string& dest) -{ - bool got_string = false; - dest.clear(); - - Locker py_lock (this, - Locker::AcquireLock | Locker::NoSTDIN, - Locker::FreeLock); - - static char callee_name[] = "get_short_help"; - - if (!cmd_obj_sp) - return false; - - PyObject* implementor = (PyObject*)cmd_obj_sp->GetValue(); - - if (implementor == nullptr || implementor == Py_None) - return false; - - PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); - - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - if (pmeth == nullptr || pmeth == Py_None) - { - Py_XDECREF(pmeth); - return false; - } - - if (PyCallable_Check(pmeth) == 0) - { - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - Py_XDECREF(pmeth); - return false; - } - - 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(); - } - - if (py_return != nullptr && py_return != Py_None) - { - if (PyString_Check(py_return)) - { - dest.assign(PyString_AsString(py_return)); - got_string = true; - } - } - Py_XDECREF(py_return); - - return got_string; -} - -uint32_t -ScriptInterpreterPython::GetFlagsForCommandObject (StructuredData::GenericSP cmd_obj_sp) -{ - uint32_t result = 0; - - Locker py_lock (this, - Locker::AcquireLock | Locker::NoSTDIN, - Locker::FreeLock); - - static char callee_name[] = "get_flags"; - - if (!cmd_obj_sp) - return result; - - PyObject* implementor = (PyObject*)cmd_obj_sp->GetValue(); - - if (implementor == nullptr || implementor == Py_None) - return result; - - PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); - - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - if (pmeth == nullptr || pmeth == Py_None) - { - Py_XDECREF(pmeth); - return result; - } - - if (PyCallable_Check(pmeth) == 0) - { - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - Py_XDECREF(pmeth); - return result; - } - - 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(); - } - - if (py_return != nullptr && py_return != Py_None) - { - if (PyInt_Check(py_return)) - result = (uint32_t)PyInt_AsLong(py_return); - else if (PyLong_Check(py_return)) - result = (uint32_t)PyLong_AsLong(py_return); - } - Py_XDECREF(py_return); - - return result; -} - -bool -ScriptInterpreterPython::GetLongHelpForCommandObject (StructuredData::GenericSP cmd_obj_sp, - std::string& dest) -{ - bool got_string = false; - dest.clear(); - - Locker py_lock (this, - Locker::AcquireLock | Locker::NoSTDIN, - Locker::FreeLock); - - static char callee_name[] = "get_long_help"; - - if (!cmd_obj_sp) - return false; - - PyObject* implementor = (PyObject*)cmd_obj_sp->GetValue(); - - if (implementor == nullptr || implementor == Py_None) - return false; - - PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); - - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - if (pmeth == nullptr || pmeth == Py_None) - { - Py_XDECREF(pmeth); - return false; - } - - if (PyCallable_Check(pmeth) == 0) - { - if (PyErr_Occurred()) - { - PyErr_Clear(); - } - - Py_XDECREF(pmeth); - return false; - } - - 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(); - } - - if (py_return != nullptr && py_return != Py_None) - { - if (PyString_Check(py_return)) - { - dest.assign(PyString_AsString(py_return)); - got_string = true; - } - } - Py_XDECREF(py_return); - - return got_string; -} - -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, - SWIGPythonCreateCommandObject swig_create_cmd, - 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, - SWIGPythonCallCommandObject swig_call_command_object, - 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_create_cmd = swig_create_cmd; - 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_command_object = swig_call_command_object; - 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 () -{ - assert(!g_initialized && "ScriptInterpreterPython::InitializePrivate() called more than once!"); - 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); - -#if defined(LLDB_PYTHON_HOME) - Py_SetPythonHome(LLDB_PYTHON_HOME); -#endif - 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); - - 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"); - AddToSysPath(AddLocation::End, "."); - - FileSpec file_spec; - // Don't denormalize paths when calling file_spec.GetPath(). On platforms that use - // a backslash as the path separator, this will result in executing python code containing - // paths with unescaped backslashes. But Python also accepts forward slashes, so to make - // life easier we just use that. - if (HostInfo::GetLLDBPath(ePathTypePythonDir, file_spec)) - AddToSysPath(AddLocation::Beginning, file_spec.GetPath(false)); - if (HostInfo::GetLLDBPath(ePathTypeLLDBShlibDir, file_spec)) - AddToSysPath(AddLocation::Beginning, file_spec.GetPath(false)); - - 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"); - - 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::AddToSysPath(AddLocation location, std::string path) -{ - std::string path_copy; - - std::string statement; - if (location == AddLocation::Beginning) - { - statement.assign("sys.path.insert(0,\""); - statement.append (path); - statement.append ("\")"); - } - else - { - statement.assign("sys.path.append(\""); - statement.append(path); - statement.append("\")"); - } - PyRun_SimpleString (statement.c_str()); -} - - -//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/Plugins/CMakeLists.txt =================================================================== --- source/Plugins/CMakeLists.txt +++ source/Plugins/CMakeLists.txt @@ -11,6 +11,7 @@ add_subdirectory(OperatingSystem) add_subdirectory(Platform) add_subdirectory(Process) +add_subdirectory(ScriptInterpreter) add_subdirectory(SymbolFile) add_subdirectory(SystemRuntime) add_subdirectory(SymbolVendor) 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/ScriptInterpreter/CMakeLists.txt =================================================================== --- /dev/null +++ source/Plugins/ScriptInterpreter/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(None) +add_subdirectory(Python) Index: source/Plugins/ScriptInterpreter/None/CMakeLists.txt =================================================================== --- /dev/null +++ source/Plugins/ScriptInterpreter/None/CMakeLists.txt @@ -0,0 +1,3 @@ +add_lldb_library(lldbPluginScriptInterpreterNone + ScriptInterpreterNone.cpp + ) \ No newline at end of file Index: source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h =================================================================== --- /dev/null +++ source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h @@ -0,0 +1,62 @@ +//===-- 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(); + + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void + Initialize(); + + static void + Terminate(); + + static lldb::ScriptInterpreterSP + CreateInstance(CommandInterpreter &interpreter); + + static lldb_private::ConstString + GetPluginNameStatic(); + + static const char * + GetPluginDescriptionStatic(); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + virtual lldb_private::ConstString + GetPluginName(); + + virtual uint32_t + GetPluginVersion(); +}; + +} // namespace lldb_private + +#endif // #ifndef liblldb_ScriptInterpreterNone_h_ Index: source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp =================================================================== --- /dev/null +++ source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp @@ -0,0 +1,93 @@ +//===-- 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 "ScriptInterpreterNone.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Stream.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Core/StringList.h" +#include "lldb/Interpreter/CommandInterpreter.h" + +#include + +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"); +} + +void +ScriptInterpreterNone::Initialize() +{ + static std::once_flag g_once_flag; + + std::call_once(g_once_flag, []() + { + PluginManager::RegisterPlugin(GetPluginNameStatic(), GetPluginDescriptionStatic(), + lldb::eScriptLanguageNone, CreateInstance); + }); +} + +void +ScriptInterpreterNone::Terminate() +{ +} + +lldb::ScriptInterpreterSP +ScriptInterpreterNone::CreateInstance(CommandInterpreter &interpreter) +{ + return std::make_shared(interpreter); +} + +lldb_private::ConstString +ScriptInterpreterNone::GetPluginNameStatic() +{ + static ConstString g_name("script-none"); + return g_name; +} + +const char * +ScriptInterpreterNone::GetPluginDescriptionStatic() +{ + return "Null script interpreter"; +} + +lldb_private::ConstString +ScriptInterpreterNone::GetPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t +ScriptInterpreterNone::GetPluginVersion() +{ + return 1; +} Index: source/Plugins/ScriptInterpreter/Python/CMakeLists.txt =================================================================== --- /dev/null +++ source/Plugins/ScriptInterpreter/Python/CMakeLists.txt @@ -0,0 +1,4 @@ +add_lldb_library(lldbPluginScriptInterpreterPython + PythonDataObjects.cpp + ScriptInterpreterPython.cpp + ) Index: source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h =================================================================== --- /dev/null +++ source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h @@ -0,0 +1,279 @@ +//===-- 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 LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONDATAOBJECTS_H +#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_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/StructuredData.h" +#include "lldb/Core/Flags.h" +#include "lldb/Interpreter/OptionValue.h" + +namespace lldb_private { +class PythonString; +class PythonList; +class PythonDictionary; +class PythonObject; +class PythonInteger; + +class StructuredPythonObject : public StructuredData::Generic +{ + public: + StructuredPythonObject() + : StructuredData::Generic() + { + } + + StructuredPythonObject(void *obj) + : StructuredData::Generic(obj) + { + Py_XINCREF(GetValue()); + } + + virtual ~StructuredPythonObject() + { + if (Py_IsInitialized()) + Py_XDECREF(GetValue()); + SetValue(nullptr); + } + + bool + IsValid() const override + { + return GetValue() && GetValue() != Py_None; + } + + void Dump(Stream &s) const override; + + private: + DISALLOW_COPY_AND_ASSIGN(StructuredPythonObject); +}; + +enum class PyObjectType +{ + Unknown, + None, + Integer, + Dictionary, + List, + String +}; + + 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); + } + + 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; + } + + PyObjectType GetObjectType() const; + + PythonString + Repr (); + + PythonString + Str (); + + explicit operator bool () const + { + return m_py_obj != NULL; + } + + bool + IsNULLOrNone () const; + + StructuredData::ObjectSP CreateStructuredObject() const; + + protected: + PyObject* m_py_obj; + }; + + class PythonString: public PythonObject + { + public: + PythonString (); + PythonString (PyObject *o); + PythonString (const PythonObject &object); + PythonString (llvm::StringRef string); + PythonString (const char *string); + virtual ~PythonString (); + + virtual bool + Reset (PyObject* py_obj = NULL); + + llvm::StringRef + GetString() const; + + size_t + GetSize() const; + + void SetString(llvm::StringRef string); + + StructuredData::StringSP CreateStructuredString() const; + }; + + class PythonInteger: public PythonObject + { + public: + + PythonInteger (); + PythonInteger (PyObject* py_obj); + PythonInteger (const PythonObject &object); + PythonInteger (int64_t value); + virtual ~PythonInteger (); + + virtual bool + Reset (PyObject* py_obj = NULL); + + int64_t GetInteger() const; + + void + SetInteger (int64_t value); + + StructuredData::IntegerSP CreateStructuredInteger() const; + }; + + class PythonList: public PythonObject + { + public: + + PythonList (bool create_empty); + PythonList (PyObject* py_obj); + PythonList (const PythonObject &object); + PythonList (uint32_t count); + virtual ~PythonList (); + + virtual bool + Reset (PyObject* py_obj = NULL); + + uint32_t GetSize() const; + + PythonObject GetItemAtIndex(uint32_t index) const; + + void + SetItemAtIndex (uint32_t index, const PythonObject &object); + + void + AppendItem (const PythonObject &object); + + StructuredData::ArraySP CreateStructuredArray() const; + }; + + class PythonDictionary: public PythonObject + { + public: + + explicit PythonDictionary (bool create_empty); + PythonDictionary (PyObject* object); + PythonDictionary (const PythonObject &object); + virtual ~PythonDictionary (); + + virtual bool + Reset (PyObject* object = NULL); + + uint32_t GetSize() const; + + 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); + + StructuredData::DictionarySP CreateStructuredDictionary() const; + }; + +} // namespace lldb_private + +#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONDATAOBJECTS_H Index: source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp =================================================================== --- /dev/null +++ source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp @@ -0,0 +1,522 @@ +//===-- PythonDataObjects.cpp ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifdef LLDB_DISABLE_PYTHON + +// Python is disabled in this build + +#else + +#include "lldb-python.h" +#include "PythonDataObjects.h" +#include "ScriptInterpreterPython.h" + +#include "lldb/Core/Stream.h" +#include "lldb/Host/File.h" +#include "lldb/Interpreter/ScriptInterpreter.h" + +#include + +using namespace lldb_private; +using namespace lldb; + +void +StructuredPythonObject::Dump(Stream &s) const +{ + s << "Python Obj: 0x" << GetValue(); +} + +//---------------------------------------------------------------------- +// PythonObject +//---------------------------------------------------------------------- + +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"); +} + +PyObjectType +PythonObject::GetObjectType() const +{ + if (IsNULLOrNone()) + return PyObjectType::None; + + if (PyList_Check(m_py_obj)) + return PyObjectType::List; + if (PyDict_Check(m_py_obj)) + return PyObjectType::Dictionary; + if (PyString_Check(m_py_obj)) + return PyObjectType::String; + if (PyInt_Check(m_py_obj) || PyLong_Check(m_py_obj)) + return PyObjectType::Integer; + return PyObjectType::Unknown; +} + +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)); +} + +StructuredData::ObjectSP +PythonObject::CreateStructuredObject() const +{ + switch (GetObjectType()) + { + case PyObjectType::Dictionary: + return PythonDictionary(m_py_obj).CreateStructuredDictionary(); + case PyObjectType::Integer: + return PythonInteger(m_py_obj).CreateStructuredInteger(); + case PyObjectType::List: + return PythonList(m_py_obj).CreateStructuredArray(); + case PyObjectType::String: + return PythonString(m_py_obj).CreateStructuredString(); + case PyObjectType::None: + return StructuredData::ObjectSP(); + default: + return StructuredData::ObjectSP(new StructuredPythonObject(m_py_obj)); + } +} + +//---------------------------------------------------------------------- +// 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 (llvm::StringRef string) : + PythonObject(PyString_FromStringAndSize(string.data(), string.size())) +{ +} + +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; +} + +llvm::StringRef +PythonString::GetString() const +{ + if (m_py_obj) + return llvm::StringRef(PyString_AsString(m_py_obj), GetSize()); + return llvm::StringRef(); +} + +size_t +PythonString::GetSize() const +{ + if (m_py_obj) + return PyString_Size(m_py_obj); + return 0; +} + +void +PythonString::SetString (llvm::StringRef string) +{ + PythonObject::Reset(PyString_FromStringAndSize(string.data(), string.size())); +} + +StructuredData::StringSP +PythonString::CreateStructuredString() const +{ + StructuredData::StringSP result(new StructuredData::String); + result->SetValue(GetString()); + return result; +} + +//---------------------------------------------------------------------- +// 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 (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() const +{ + 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)); +} + +StructuredData::IntegerSP +PythonInteger::CreateStructuredInteger() const +{ + StructuredData::IntegerSP result(new StructuredData::Integer); + result->SetValue(GetInteger()); + return result; +} + +//---------------------------------------------------------------------- +// 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 () +{ +} + +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() const +{ + if (m_py_obj) + return PyList_GET_SIZE(m_py_obj); + return 0; +} + +PythonObject +PythonList::GetItemAtIndex(uint32_t index) const +{ + 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()); +} + +StructuredData::ArraySP +PythonList::CreateStructuredArray() const +{ + StructuredData::ArraySP result(new StructuredData::Array); + uint32_t count = GetSize(); + for (uint32_t i = 0; i < count; ++i) + { + PythonObject obj = GetItemAtIndex(i); + result->AddItem(obj.CreateStructuredObject()); + } + return result; +} + +//---------------------------------------------------------------------- +// 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 () +{ +} + +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() const +{ + 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()); +} + +StructuredData::DictionarySP +PythonDictionary::CreateStructuredDictionary() const +{ + StructuredData::DictionarySP result(new StructuredData::Dictionary); + PythonList keys(GetKeys()); + uint32_t num_keys = keys.GetSize(); + for (uint32_t i = 0; i < num_keys; ++i) + { + PythonObject key = keys.GetItemAtIndex(i); + PythonString key_str = key.Str(); + PythonObject value = GetItemForKey(key); + StructuredData::ObjectSP structured_value = value.CreateStructuredObject(); + result->AddItem(key_str.GetString(), structured_value); + } + return result; +} + +#endif Index: source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h =================================================================== --- /dev/null +++ source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h @@ -0,0 +1,590 @@ +//===-- 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 LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTINTERPRETERPYTHON_H +#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTINTERPRETERPYTHON_H + +#ifdef LLDB_DISABLE_PYTHON + +// Python is disabled in this build + +#else + +#include "lldb/lldb-private.h" +#include "PythonDataObjects.h" +#include "lldb/Core/IOHandler.h" +#include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/Host/Terminal.h" + +class IOHandlerPythonInterpreter; + +namespace lldb_private { + +class ScriptInterpreterPython : + public ScriptInterpreter, + public IOHandlerDelegateMultiline +{ +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* (*SWIGPythonCreateCommandObject) (const char *python_class_name, + const char *session_dictionary_name, + const lldb::DebuggerSP debugger_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 size_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 (*SWIGPythonCallCommandObject) (void *implementor, + 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); + + 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; + + StructuredData::ObjectSP CreateSyntheticScriptedProvider(const char *class_name, lldb::ValueObjectSP valobj) override; + + StructuredData::GenericSP CreateScriptCommandObject (const char *class_name) override; + + StructuredData::ObjectSP CreateScriptedThreadPlan(const char *class_name, lldb::ThreadPlanSP thread_plan) override; + + bool ScriptedThreadPlanExplainsStop(StructuredData::ObjectSP implementor_sp, Event *event, bool &script_error) override; + bool ScriptedThreadPlanShouldStop(StructuredData::ObjectSP implementor_sp, Event *event, bool &script_error) override; + lldb::StateType ScriptedThreadPlanGetRunState(StructuredData::ObjectSP implementor_sp, bool &script_error) override; + + StructuredData::GenericSP OSPlugin_CreatePluginObject(const char *class_name, lldb::ProcessSP process_sp) override; + + StructuredData::DictionarySP OSPlugin_RegisterInfo(StructuredData::ObjectSP os_plugin_object_sp) override; + + StructuredData::ArraySP OSPlugin_ThreadsInfo(StructuredData::ObjectSP os_plugin_object_sp) override; + + StructuredData::StringSP OSPlugin_RegisterContextData(StructuredData::ObjectSP os_plugin_object_sp, lldb::tid_t thread_id) override; + + StructuredData::DictionarySP OSPlugin_CreateThread(StructuredData::ObjectSP os_plugin_object_sp, lldb::tid_t tid, + lldb::addr_t context) override; + + StructuredData::ObjectSP LoadPluginModule(const FileSpec &file_spec, lldb_private::Error &error) override; + + StructuredData::DictionarySP GetDynamicSettings(StructuredData::ObjectSP plugin_module_sp, Target *target, const char *setting_name, + lldb_private::Error &error) override; + + size_t CalculateNumChildren(const StructuredData::ObjectSP &implementor) override; + + lldb::ValueObjectSP GetChildAtIndex(const StructuredData::ObjectSP &implementor, uint32_t idx) override; + + int GetIndexOfChildWithName(const StructuredData::ObjectSP &implementor, const char *child_name) override; + + bool UpdateSynthProviderInstance(const StructuredData::ObjectSP &implementor) override; + + bool MightHaveChildrenSynthProviderInstance(const StructuredData::ObjectSP &implementor) override; + + lldb::ValueObjectSP GetSyntheticValue(const StructuredData::ObjectSP &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; + + bool + RunScriptBasedCommand (StructuredData::GenericSP impl_obj_sp, + 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, StructuredData::ObjectSP &callee_wrapper_sp, + const TypeSummaryOptions &options, std::string &retval) override; + + void + Clear () override; + + bool + GetDocumentationForItem (const char* item, std::string& dest) override; + + bool + GetShortHelpForCommandObject(StructuredData::GenericSP cmd_obj_sp, std::string& dest) override; + + uint32_t + GetFlagsForCommandObject (StructuredData::GenericSP cmd_obj_sp) override; + + bool + GetLongHelpForCommandObject(StructuredData::GenericSP cmd_obj_sp, 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, + StructuredData::ObjectSP *module_sp = nullptr) override; + + bool + IsReservedWord (const char* word) 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); + + 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, + SWIGPythonCreateCommandObject swig_create_cmd, + 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, + SWIGPythonCallCommandObject swig_call_command_object, + 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; + + + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void + Initialize(); + + static void + Terminate(); + + static lldb::ScriptInterpreterSP + CreateInstance(CommandInterpreter &interpreter); + + static lldb_private::ConstString + GetPluginNameStatic(); + + static const char * + GetPluginDescriptionStatic(); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + virtual lldb_private::ConstString + GetPluginName(); + + virtual uint32_t + GetPluginVersion(); + +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(); + }; + +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: + enum class AddLocation + { + Beginning, + End + }; + + static void AddToSysPath(AddLocation location, std::string path); + + 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 LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTINTERPRETERPYTHON_H Index: source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp =================================================================== --- /dev/null +++ source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -0,0 +1,3255 @@ +//===-- ScriptInterpreterPython.cpp -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifdef LLDB_DISABLE_PYTHON + +// Python is disabled in this build + +#else + +#include "lldb-python.h" +#include "ScriptInterpreterPython.h" +#include "PythonDataObjects.h" + +#include +#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/PluginManager.h" +#include "lldb/Core/Timer.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/DataFormatters/TypeSummary.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/Target/Thread.h" +#include "lldb/Target/ThreadPlan.h" + +#if defined(_WIN32) +#include "lldb/Host/windows/ConnectionGenericFileWindows.h" +#endif + +#include "llvm/ADT/StringRef.h" + +using namespace lldb; +using namespace lldb_private; + +static ScriptInterpreterPython::SWIGInitCallback g_swig_init_callback = nullptr; +static ScriptInterpreterPython::SWIGBreakpointCallbackFunction g_swig_breakpoint_callback = nullptr; +static ScriptInterpreterPython::SWIGWatchpointCallbackFunction g_swig_watchpoint_callback = nullptr; +static ScriptInterpreterPython::SWIGPythonTypeScriptCallbackFunction g_swig_typescript_callback = nullptr; +static ScriptInterpreterPython::SWIGPythonCreateSyntheticProvider g_swig_synthetic_script = nullptr; +static ScriptInterpreterPython::SWIGPythonCreateCommandObject g_swig_create_cmd = nullptr; +static ScriptInterpreterPython::SWIGPythonCalculateNumChildren g_swig_calc_children = nullptr; +static ScriptInterpreterPython::SWIGPythonGetChildAtIndex g_swig_get_child_index = nullptr; +static ScriptInterpreterPython::SWIGPythonGetIndexOfChildWithName g_swig_get_index_child = nullptr; +static ScriptInterpreterPython::SWIGPythonCastPyObjectToSBValue g_swig_cast_to_sbvalue = nullptr; +static ScriptInterpreterPython::SWIGPythonGetValueObjectSPFromSBValue g_swig_get_valobj_sp_from_sbvalue = nullptr; +static ScriptInterpreterPython::SWIGPythonUpdateSynthProviderInstance g_swig_update_provider = nullptr; +static ScriptInterpreterPython::SWIGPythonMightHaveChildrenSynthProviderInstance g_swig_mighthavechildren_provider = nullptr; +static ScriptInterpreterPython::SWIGPythonGetValueSynthProviderInstance g_swig_getvalue_provider = nullptr; +static ScriptInterpreterPython::SWIGPythonCallCommand g_swig_call_command = nullptr; +static ScriptInterpreterPython::SWIGPythonCallCommandObject g_swig_call_command_object = nullptr; +static ScriptInterpreterPython::SWIGPythonCallModuleInit g_swig_call_module_init = nullptr; +static ScriptInterpreterPython::SWIGPythonCreateOSPlugin g_swig_create_os_plugin = nullptr; +static ScriptInterpreterPython::SWIGPythonScriptKeyword_Process g_swig_run_script_keyword_process = nullptr; +static ScriptInterpreterPython::SWIGPythonScriptKeyword_Thread g_swig_run_script_keyword_thread = nullptr; +static ScriptInterpreterPython::SWIGPythonScriptKeyword_Target g_swig_run_script_keyword_target = nullptr; +static ScriptInterpreterPython::SWIGPythonScriptKeyword_Frame g_swig_run_script_keyword_frame = nullptr; +static ScriptInterpreterPython::SWIGPythonScriptKeyword_Value g_swig_run_script_keyword_value = nullptr; +static ScriptInterpreterPython::SWIGPython_GetDynamicSetting g_swig_plugin_get = nullptr; +static ScriptInterpreterPython::SWIGPythonCreateScriptedThreadPlan g_swig_thread_plan_script = nullptr; +static ScriptInterpreterPython::SWIGPythonCallThreadPlan g_swig_call_thread_plan = nullptr; + +static bool g_initialized = false; + +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) +{ + assert(g_initialized && "ScriptInterpreterPython created but InitializePrivate has not been called!"); + + 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(); + + 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(); + + 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 () +{ + // the session dictionary may hold objects with complex state + // which means that they may need to be torn down with some level of smarts + // and that, in turn, requires a valid thread state + // force Python to procure itself such a thread state, nuke the session dictionary + // and then release it for others to use and proceed with the rest of the shutdown + auto gil_state = PyGILState_Ensure(); + m_session_dict.Reset(); + PyGILState_Release(gil_state); +} + +void +ScriptInterpreterPython::Initialize() +{ + static std::once_flag g_once_flag; + + std::call_once(g_once_flag, []() + { + InitializePrivate(); + + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), + lldb::eScriptLanguagePython, + CreateInstance); + }); +} + +void +ScriptInterpreterPython::Terminate() +{ + +} + +lldb::ScriptInterpreterSP +ScriptInterpreterPython::CreateInstance(CommandInterpreter &interpreter) +{ + return std::make_shared(interpreter); +} + +lldb_private::ConstString +ScriptInterpreterPython::GetPluginNameStatic() +{ + static ConstString g_name("script-python"); + return g_name; +} + +const char * +ScriptInterpreterPython::GetPluginDescriptionStatic() +{ + return "Embedded Python interpreter"; +} + +lldb_private::ConstString +ScriptInterpreterPython::GetPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t +ScriptInterpreterPython::GetPluginVersion() +{ + return 1; +} + +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; +} + +static PyObject * +PyFile_FromFile_Const(FILE *fp, const char *name, const char *mode, int (*close)(FILE *)) +{ + // Read through the Python source, doesn't seem to modify these strings + return PyFile_FromFile(fp, const_cast(name), const_cast(mode), close); +} + +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_Const (in, "", "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_Const (out, "", "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_Const (err, "", "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) + { + + } + + ~IOHandlerPythonInterpreter() override + { + + } + + ConstString + GetControlSequence (char ch) override + { + if (ch == 'd') + return ConstString("quit()\n"); + return ConstString(); + } + + void + Run () override + { + 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); + } + + void + Cancel () override + { + + } + + bool + Interrupt () override + { + return m_python->Interrupt(); + } + + void + GotEOF() override + { + + } +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; +} + +StructuredData::GenericSP +ScriptInterpreterPython::OSPlugin_CreatePluginObject(const char *class_name, lldb::ProcessSP process_sp) +{ + if (class_name == nullptr || class_name[0] == '\0') + return StructuredData::GenericSP(); + + if (!process_sp) + return StructuredData::GenericSP(); + + 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 StructuredData::GenericSP(new StructuredPythonObject(ret_val)); +} + +StructuredData::DictionarySP +ScriptInterpreterPython::OSPlugin_RegisterInfo(StructuredData::ObjectSP 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 StructuredData::DictionarySP(); + + StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric(); + if (!generic) + return nullptr; + + PyObject *implementor = (PyObject *)generic->GetValue(); + + if (implementor == nullptr || implementor == Py_None) + return StructuredData::DictionarySP(); + + PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); + + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + if (pmeth == nullptr || pmeth == Py_None) + { + Py_XDECREF(pmeth); + return StructuredData::DictionarySP(); + } + + if (PyCallable_Check(pmeth) == 0) + { + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + Py_XDECREF(pmeth); + return StructuredData::DictionarySP(); + } + + 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(); + } + + PythonDictionary result_dict(py_return); + return result_dict.CreateStructuredDictionary(); +} + +StructuredData::ArraySP +ScriptInterpreterPython::OSPlugin_ThreadsInfo(StructuredData::ObjectSP 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 StructuredData::ArraySP(); + + StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric(); + if (!generic) + return nullptr; + PyObject *implementor = (PyObject *)generic->GetValue(); + + if (implementor == nullptr || implementor == Py_None) + return StructuredData::ArraySP(); + + PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); + + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + if (pmeth == nullptr || pmeth == Py_None) + { + Py_XDECREF(pmeth); + return StructuredData::ArraySP(); + } + + if (PyCallable_Check(pmeth) == 0) + { + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + Py_XDECREF(pmeth); + return StructuredData::ArraySP(); + } + + 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(); + } + + PythonList ResultList(py_return); + return ResultList.CreateStructuredArray(); +} + +// 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"; } + +StructuredData::StringSP +ScriptInterpreterPython::OSPlugin_RegisterContextData(StructuredData::ObjectSP 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 StructuredData::StringSP(); + + StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric(); + if (!generic) + return nullptr; + PyObject *implementor = (PyObject *)generic->GetValue(); + + if (implementor == nullptr || implementor == Py_None) + return StructuredData::StringSP(); + + PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); + + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + if (pmeth == nullptr || pmeth == Py_None) + { + Py_XDECREF(pmeth); + return StructuredData::StringSP(); + } + + if (PyCallable_Check(pmeth) == 0) + { + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + Py_XDECREF(pmeth); + return StructuredData::StringSP(); + } + + 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(); + } + PythonString result_string(py_return); + return result_string.CreateStructuredString(); +} + +StructuredData::DictionarySP +ScriptInterpreterPython::OSPlugin_CreateThread(StructuredData::ObjectSP 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 StructuredData::DictionarySP(); + + StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric(); + if (!generic) + return nullptr; + PyObject *implementor = (PyObject *)generic->GetValue(); + + if (implementor == nullptr || implementor == Py_None) + return StructuredData::DictionarySP(); + + PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); + + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + if (pmeth == nullptr || pmeth == Py_None) + { + Py_XDECREF(pmeth); + return StructuredData::DictionarySP(); + } + + if (PyCallable_Check(pmeth) == 0) + { + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + Py_XDECREF(pmeth); + return StructuredData::DictionarySP(); + } + + 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(); + } + + PythonDictionary result_dict(py_return); + return result_dict.CreateStructuredDictionary(); +} + +StructuredData::ObjectSP +ScriptInterpreterPython::CreateScriptedThreadPlan(const char *class_name, lldb::ThreadPlanSP thread_plan_sp) +{ + if (class_name == nullptr || class_name[0] == '\0') + return StructuredData::ObjectSP(); + + if (!thread_plan_sp.get()) + return StructuredData::ObjectSP(); + + Debugger &debugger = thread_plan_sp->GetTarget().GetDebugger(); + ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter(); + ScriptInterpreterPython *python_interpreter = static_cast(script_interpreter); + + if (!script_interpreter) + return StructuredData::ObjectSP(); + + 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 StructuredData::ObjectSP(new StructuredPythonObject(ret_val)); +} + +bool +ScriptInterpreterPython::ScriptedThreadPlanExplainsStop(StructuredData::ObjectSP implementor_sp, Event *event, bool &script_error) +{ + bool explains_stop = true; + StructuredData::Generic *generic = nullptr; + if (implementor_sp) + generic = implementor_sp->GetAsGeneric(); + if (generic) + { + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + explains_stop = g_swig_call_thread_plan(generic->GetValue(), "explains_stop", event, script_error); + if (script_error) + return true; + } + return explains_stop; +} + +bool +ScriptInterpreterPython::ScriptedThreadPlanShouldStop(StructuredData::ObjectSP implementor_sp, Event *event, bool &script_error) +{ + bool should_stop = true; + StructuredData::Generic *generic = nullptr; + if (implementor_sp) + generic = implementor_sp->GetAsGeneric(); + if (generic) + { + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + should_stop = g_swig_call_thread_plan(generic->GetValue(), "should_stop", event, script_error); + if (script_error) + return true; + } + return should_stop; +} + +lldb::StateType +ScriptInterpreterPython::ScriptedThreadPlanGetRunState(StructuredData::ObjectSP implementor_sp, bool &script_error) +{ + bool should_step = false; + StructuredData::Generic *generic = nullptr; + if (implementor_sp) + generic = implementor_sp->GetAsGeneric(); + if (generic) + { + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + should_step = g_swig_call_thread_plan(generic->GetValue(), "should_step", NULL, script_error); + if (script_error) + should_step = true; + } + if (should_step) + return lldb::eStateStepping; + else + return lldb::eStateRunning; +} + +StructuredData::ObjectSP +ScriptInterpreterPython::LoadPluginModule(const FileSpec &file_spec, lldb_private::Error &error) +{ + if (!file_spec.Exists()) + { + error.SetErrorString("no such file"); + return StructuredData::ObjectSP(); + } + + StructuredData::ObjectSP module_sp; + + if (LoadScriptingModule(file_spec.GetPath().c_str(),true,true,error,&module_sp)) + return module_sp; + + return StructuredData::ObjectSP(); +} + +StructuredData::DictionarySP +ScriptInterpreterPython::GetDynamicSettings(StructuredData::ObjectSP plugin_module_sp, Target *target, const char *setting_name, + lldb_private::Error &error) +{ + if (!plugin_module_sp || !target || !setting_name || !setting_name[0] || !g_swig_plugin_get) + return StructuredData::DictionarySP(); + StructuredData::Generic *generic = plugin_module_sp->GetAsGeneric(); + if (!generic) + return StructuredData::DictionarySP(); + + 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(generic->GetValue(), setting_name, target_sp); + } + + PythonDictionary py_dict(reply_pyobj); + + return py_dict.CreateStructuredDictionary(); +} + +StructuredData::ObjectSP +ScriptInterpreterPython::CreateSyntheticScriptedProvider(const char *class_name, lldb::ValueObjectSP valobj) +{ + if (class_name == nullptr || class_name[0] == '\0') + return StructuredData::ObjectSP(); + + if (!valobj.get()) + return StructuredData::ObjectSP(); + + ExecutionContext exe_ctx (valobj->GetExecutionContextRef()); + Target *target = exe_ctx.GetTargetPtr(); + + if (!target) + return StructuredData::ObjectSP(); + + Debugger &debugger = target->GetDebugger(); + ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter(); + ScriptInterpreterPython *python_interpreter = (ScriptInterpreterPython *) script_interpreter; + + if (!script_interpreter) + return StructuredData::ObjectSP(); + + void *ret_val = nullptr; + + { + 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 StructuredData::ObjectSP(new StructuredPythonObject(ret_val)); +} + +StructuredData::GenericSP +ScriptInterpreterPython::CreateScriptCommandObject (const char *class_name) +{ + DebuggerSP debugger_sp(GetCommandInterpreter().GetDebugger().shared_from_this()); + + if (class_name == nullptr || class_name[0] == '\0') + return StructuredData::GenericSP(); + + if (!debugger_sp.get()) + return StructuredData::GenericSP(); + + void* ret_val; + + { + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + ret_val = g_swig_create_cmd (class_name, + m_dictionary_name.c_str(), + debugger_sp); + } + + return StructuredData::GenericSP(new StructuredPythonObject(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, + StructuredData::ObjectSP &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 = nullptr; + StructuredData::Generic *generic = nullptr; + if (callee_wrapper_sp) + { + generic = callee_wrapper_sp->GetAsGeneric(); + if (generic) + old_callee = generic->GetValue(); + } + 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.reset(new StructuredPythonObject(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 StructuredData::ObjectSP &implementor_sp) +{ + if (!implementor_sp) + return 0; + StructuredData::Generic *generic = implementor_sp->GetAsGeneric(); + if (!generic) + return 0; + void *implementor = generic->GetValue(); + if (!implementor) + return 0; + + if (!g_swig_calc_children) + return 0; + + size_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 StructuredData::ObjectSP &implementor_sp, uint32_t idx) +{ + if (!implementor_sp) + return lldb::ValueObjectSP(); + + StructuredData::Generic *generic = implementor_sp->GetAsGeneric(); + if (!generic) + return lldb::ValueObjectSP(); + void *implementor = generic->GetValue(); + 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 StructuredData::ObjectSP &implementor_sp, const char *child_name) +{ + if (!implementor_sp) + return UINT32_MAX; + + StructuredData::Generic *generic = implementor_sp->GetAsGeneric(); + if (!generic) + return UINT32_MAX; + void *implementor = generic->GetValue(); + 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 StructuredData::ObjectSP &implementor_sp) +{ + bool ret_val = false; + + if (!implementor_sp) + return ret_val; + + StructuredData::Generic *generic = implementor_sp->GetAsGeneric(); + if (!generic) + return ret_val; + void *implementor = generic->GetValue(); + 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 StructuredData::ObjectSP &implementor_sp) +{ + bool ret_val = false; + + if (!implementor_sp) + return ret_val; + + StructuredData::Generic *generic = implementor_sp->GetAsGeneric(); + if (!generic) + return ret_val; + void *implementor = generic->GetValue(); + 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 StructuredData::ObjectSP &implementor_sp) +{ + lldb::ValueObjectSP ret_val(nullptr); + + if (!implementor_sp) + return ret_val; + + StructuredData::Generic *generic = implementor_sp->GetAsGeneric(); + if (!generic) + return ret_val; + void *implementor = generic->GetValue(); + 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, + StructuredData::ObjectSP *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->reset(new StructuredPythonObject(module_pyobj)); + } + + return true; + } +} + +bool +ScriptInterpreterPython::IsReservedWord (const char* word) +{ + if (!word || !word[0]) + return false; + + llvm::StringRef word_sr(word); + + // filter out a few characters that would just confuse us + // and that are clearly not keyword material anyway + if (word_sr.find_first_of("'\"") != llvm::StringRef::npos) + return false; + + 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; +} + +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; +} + +bool +ScriptInterpreterPython::RunScriptBasedCommand (StructuredData::GenericSP impl_obj_sp, + const char* args, + ScriptedCommandSynchronicity synchronicity, + lldb_private::CommandReturnObject& cmd_retobj, + Error& error, + const lldb_private::ExecutionContext& exe_ctx) +{ + if (!impl_obj_sp || !impl_obj_sp->IsValid()) + { + error.SetErrorString("no function to execute"); + return false; + } + + if (!g_swig_call_command_object) + { + 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_object (impl_obj_sp->GetValue(), + 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; + } +} + +bool +ScriptInterpreterPython::GetShortHelpForCommandObject (StructuredData::GenericSP cmd_obj_sp, + std::string& dest) +{ + bool got_string = false; + dest.clear(); + + Locker py_lock (this, + Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); + + static char callee_name[] = "get_short_help"; + + if (!cmd_obj_sp) + return false; + + PyObject* implementor = (PyObject*)cmd_obj_sp->GetValue(); + + if (implementor == nullptr || implementor == Py_None) + return false; + + PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); + + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + if (pmeth == nullptr || pmeth == Py_None) + { + Py_XDECREF(pmeth); + return false; + } + + if (PyCallable_Check(pmeth) == 0) + { + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + Py_XDECREF(pmeth); + return false; + } + + 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(); + } + + if (py_return != nullptr && py_return != Py_None) + { + if (PyString_Check(py_return)) + { + dest.assign(PyString_AsString(py_return)); + got_string = true; + } + } + Py_XDECREF(py_return); + + return got_string; +} + +uint32_t +ScriptInterpreterPython::GetFlagsForCommandObject (StructuredData::GenericSP cmd_obj_sp) +{ + uint32_t result = 0; + + Locker py_lock (this, + Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); + + static char callee_name[] = "get_flags"; + + if (!cmd_obj_sp) + return result; + + PyObject* implementor = (PyObject*)cmd_obj_sp->GetValue(); + + if (implementor == nullptr || implementor == Py_None) + return result; + + PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); + + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + if (pmeth == nullptr || pmeth == Py_None) + { + Py_XDECREF(pmeth); + return result; + } + + if (PyCallable_Check(pmeth) == 0) + { + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + Py_XDECREF(pmeth); + return result; + } + + 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(); + } + + if (py_return != nullptr && py_return != Py_None) + { + if (PyInt_Check(py_return)) + result = (uint32_t)PyInt_AsLong(py_return); + else if (PyLong_Check(py_return)) + result = (uint32_t)PyLong_AsLong(py_return); + } + Py_XDECREF(py_return); + + return result; +} + +bool +ScriptInterpreterPython::GetLongHelpForCommandObject (StructuredData::GenericSP cmd_obj_sp, + std::string& dest) +{ + bool got_string = false; + dest.clear(); + + Locker py_lock (this, + Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); + + static char callee_name[] = "get_long_help"; + + if (!cmd_obj_sp) + return false; + + PyObject* implementor = (PyObject*)cmd_obj_sp->GetValue(); + + if (implementor == nullptr || implementor == Py_None) + return false; + + PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); + + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + if (pmeth == nullptr || pmeth == Py_None) + { + Py_XDECREF(pmeth); + return false; + } + + if (PyCallable_Check(pmeth) == 0) + { + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + Py_XDECREF(pmeth); + return false; + } + + 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(); + } + + if (py_return != nullptr && py_return != Py_None) + { + if (PyString_Check(py_return)) + { + dest.assign(PyString_AsString(py_return)); + got_string = true; + } + } + Py_XDECREF(py_return); + + return got_string; +} + +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, + SWIGPythonCreateCommandObject swig_create_cmd, + 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, + SWIGPythonCallCommandObject swig_call_command_object, + 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_create_cmd = swig_create_cmd; + 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_command_object = swig_call_command_object; + 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 () +{ + assert(!g_initialized && "ScriptInterpreterPython::InitializePrivate() called more than once!"); + 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); + +#if defined(LLDB_PYTHON_HOME) + Py_SetPythonHome(LLDB_PYTHON_HOME); +#endif + 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); + + 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"); + AddToSysPath(AddLocation::End, "."); + + FileSpec file_spec; + // Don't denormalize paths when calling file_spec.GetPath(). On platforms that use + // a backslash as the path separator, this will result in executing python code containing + // paths with unescaped backslashes. But Python also accepts forward slashes, so to make + // life easier we just use that. + if (HostInfo::GetLLDBPath(ePathTypePythonDir, file_spec)) + AddToSysPath(AddLocation::Beginning, file_spec.GetPath(false)); + if (HostInfo::GetLLDBPath(ePathTypeLLDBShlibDir, file_spec)) + AddToSysPath(AddLocation::Beginning, file_spec.GetPath(false)); + + 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"); + + 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::AddToSysPath(AddLocation location, std::string path) +{ + std::string path_copy; + + std::string statement; + if (location == AddLocation::Beginning) + { + statement.assign("sys.path.insert(0,\""); + statement.append (path); + statement.append ("\")"); + } + else + { + statement.assign("sys.path.append(\""); + statement.append(path); + statement.append("\")"); + } + PyRun_SimpleString (statement.c_str()); +} + + +//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/Plugins/ScriptInterpreter/Python/lldb-python.h =================================================================== --- /dev/null +++ source/Plugins/ScriptInterpreter/Python/lldb-python.h @@ -0,0 +1,31 @@ +//===-- lldb-python.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_LLDB_PYTHON_H +#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_LLDB_PYTHON_H + +// Python.h needs to be included before any system headers in order to avoid redefinition of macros + +#ifdef LLDB_DISABLE_PYTHON +// Python is disabled in this build +#else +#if defined(__linux__) +// features.h will define _POSIX_C_SOURCE if _GNU_SOURCE is defined. This value +// may be different from the value that Python defines it to be which results +// in a warning. Undefine _POSIX_C_SOURCE before including Python.h The same +// holds for _XOPEN_SOURCE. +#undef _POSIX_C_SOURCE +#undef _XOPEN_SOURCE +#endif + +// Include python for non windows machines +#include +#endif // LLDB_DISABLE_PYTHON + +#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_LLDB_PYTHON_H Index: unittests/CMakeLists.txt =================================================================== --- unittests/CMakeLists.txt +++ unittests/CMakeLists.txt @@ -18,10 +18,6 @@ ${ARGN} ) - if (MSVC) - target_link_libraries(${test_name} ${PYTHON_LIBRARY}) - endif() - lldb_link_common_libs(${test_name} EXE) target_link_libraries(${test_name} ${CLANG_USED_LIBS} ${LLDB_SYSTEM_LIBS}) llvm_config(${test_name} ${LLVM_LINK_COMPONENTS})