Path: blob/main/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
39638 views
//===-- ScriptInterpreterPythonImpl.h ---------------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTINTERPRETERPYTHONIMPL_H9#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTINTERPRETERPYTHONIMPL_H1011#include "lldb/Host/Config.h"1213#if LLDB_ENABLE_PYTHON1415#include "lldb-python.h"1617#include "PythonDataObjects.h"18#include "ScriptInterpreterPython.h"1920#include "lldb/Host/Terminal.h"21#include "lldb/Utility/StreamString.h"2223#include "llvm/ADT/STLExtras.h"24#include "llvm/ADT/StringRef.h"2526namespace lldb_private {27class IOHandlerPythonInterpreter;28class ScriptInterpreterPythonImpl : public ScriptInterpreterPython {29public:30friend class IOHandlerPythonInterpreter;3132ScriptInterpreterPythonImpl(Debugger &debugger);3334~ScriptInterpreterPythonImpl() override;3536bool Interrupt() override;3738bool ExecuteOneLine(39llvm::StringRef command, CommandReturnObject *result,40const ExecuteScriptOptions &options = ExecuteScriptOptions()) override;4142void ExecuteInterpreterLoop() override;4344bool ExecuteOneLineWithReturn(45llvm::StringRef in_string,46ScriptInterpreter::ScriptReturnType return_type, void *ret_value,47const ExecuteScriptOptions &options = ExecuteScriptOptions()) override;4849lldb_private::Status ExecuteMultipleLines(50const char *in_string,51const ExecuteScriptOptions &options = ExecuteScriptOptions()) override;5253Status54ExportFunctionDefinitionToInterpreter(StringList &function_def) override;5556bool GenerateTypeScriptFunction(StringList &input, std::string &output,57const void *name_token = nullptr) override;5859bool GenerateTypeSynthClass(StringList &input, std::string &output,60const void *name_token = nullptr) override;6162bool GenerateTypeSynthClass(const char *oneliner, std::string &output,63const void *name_token = nullptr) override;6465// use this if the function code is just a one-liner script66bool GenerateTypeScriptFunction(const char *oneliner, std::string &output,67const void *name_token = nullptr) override;6869bool GenerateScriptAliasFunction(StringList &input,70std::string &output) override;7172StructuredData::ObjectSP73CreateSyntheticScriptedProvider(const char *class_name,74lldb::ValueObjectSP valobj) override;7576StructuredData::GenericSP77CreateScriptCommandObject(const char *class_name) override;7879StructuredData::ObjectSP80CreateStructuredDataFromScriptObject(ScriptObject obj) override;8182StructuredData::GenericSP83CreateScriptedBreakpointResolver(const char *class_name,84const StructuredDataImpl &args_data,85lldb::BreakpointSP &bkpt_sp) override;86bool ScriptedBreakpointResolverSearchCallback(87StructuredData::GenericSP implementor_sp,88SymbolContext *sym_ctx) override;8990lldb::SearchDepth ScriptedBreakpointResolverSearchDepth(91StructuredData::GenericSP implementor_sp) override;9293StructuredData::GenericSP94CreateScriptedStopHook(lldb::TargetSP target_sp, const char *class_name,95const StructuredDataImpl &args_data,96Status &error) override;9798bool ScriptedStopHookHandleStop(StructuredData::GenericSP implementor_sp,99ExecutionContext &exc_ctx,100lldb::StreamSP stream_sp) override;101102StructuredData::GenericSP103CreateFrameRecognizer(const char *class_name) override;104105lldb::ValueObjectListSP106GetRecognizedArguments(const StructuredData::ObjectSP &implementor,107lldb::StackFrameSP frame_sp) override;108109lldb::ScriptedProcessInterfaceUP CreateScriptedProcessInterface() override;110111lldb::ScriptedThreadInterfaceSP CreateScriptedThreadInterface() override;112113lldb::ScriptedThreadPlanInterfaceSP114CreateScriptedThreadPlanInterface() override;115116lldb::OperatingSystemInterfaceSP CreateOperatingSystemInterface() override;117118StructuredData::ObjectSP119LoadPluginModule(const FileSpec &file_spec,120lldb_private::Status &error) override;121122StructuredData::DictionarySP123GetDynamicSettings(StructuredData::ObjectSP plugin_module_sp, Target *target,124const char *setting_name,125lldb_private::Status &error) override;126127size_t CalculateNumChildren(const StructuredData::ObjectSP &implementor,128uint32_t max) override;129130lldb::ValueObjectSP131GetChildAtIndex(const StructuredData::ObjectSP &implementor,132uint32_t idx) override;133134int GetIndexOfChildWithName(const StructuredData::ObjectSP &implementor,135const char *child_name) override;136137bool UpdateSynthProviderInstance(138const StructuredData::ObjectSP &implementor) override;139140bool MightHaveChildrenSynthProviderInstance(141const StructuredData::ObjectSP &implementor) override;142143lldb::ValueObjectSP144GetSyntheticValue(const StructuredData::ObjectSP &implementor) override;145146ConstString147GetSyntheticTypeName(const StructuredData::ObjectSP &implementor) override;148149bool150RunScriptBasedCommand(const char *impl_function, llvm::StringRef args,151ScriptedCommandSynchronicity synchronicity,152lldb_private::CommandReturnObject &cmd_retobj,153Status &error,154const lldb_private::ExecutionContext &exe_ctx) override;155156bool RunScriptBasedCommand(157StructuredData::GenericSP impl_obj_sp, llvm::StringRef args,158ScriptedCommandSynchronicity synchronicity,159lldb_private::CommandReturnObject &cmd_retobj, Status &error,160const lldb_private::ExecutionContext &exe_ctx) override;161162bool RunScriptBasedParsedCommand(163StructuredData::GenericSP impl_obj_sp, Args &args,164ScriptedCommandSynchronicity synchronicity,165lldb_private::CommandReturnObject &cmd_retobj, Status &error,166const lldb_private::ExecutionContext &exe_ctx) override;167168std::optional<std::string>169GetRepeatCommandForScriptedCommand(StructuredData::GenericSP impl_obj_sp,170Args &args) override;171172Status GenerateFunction(const char *signature, const StringList &input,173bool is_callback) override;174175Status GenerateBreakpointCommandCallbackData(StringList &input,176std::string &output,177bool has_extra_args,178bool is_callback) override;179180bool GenerateWatchpointCommandCallbackData(StringList &input,181std::string &output,182bool is_callback) override;183184bool GetScriptedSummary(const char *function_name, lldb::ValueObjectSP valobj,185StructuredData::ObjectSP &callee_wrapper_sp,186const TypeSummaryOptions &options,187std::string &retval) override;188189bool FormatterCallbackFunction(const char *function_name,190lldb::TypeImplSP type_impl_sp) override;191192bool GetDocumentationForItem(const char *item, std::string &dest) override;193194bool GetShortHelpForCommandObject(StructuredData::GenericSP cmd_obj_sp,195std::string &dest) override;196197uint32_t198GetFlagsForCommandObject(StructuredData::GenericSP cmd_obj_sp) override;199200bool GetLongHelpForCommandObject(StructuredData::GenericSP cmd_obj_sp,201std::string &dest) override;202203StructuredData::ObjectSP204GetOptionsForCommandObject(StructuredData::GenericSP cmd_obj_sp) override;205206StructuredData::ObjectSP207GetArgumentsForCommandObject(StructuredData::GenericSP cmd_obj_sp) override;208209bool SetOptionValueForCommandObject(StructuredData::GenericSP cmd_obj_sp,210ExecutionContext *exe_ctx,211llvm::StringRef long_option,212llvm::StringRef value) override;213214void OptionParsingStartedForCommandObject(215StructuredData::GenericSP cmd_obj_sp) override;216217bool CheckObjectExists(const char *name) override {218if (!name || !name[0])219return false;220std::string temp;221return GetDocumentationForItem(name, temp);222}223224bool RunScriptFormatKeyword(const char *impl_function, Process *process,225std::string &output, Status &error) override;226227bool RunScriptFormatKeyword(const char *impl_function, Thread *thread,228std::string &output, Status &error) override;229230bool RunScriptFormatKeyword(const char *impl_function, Target *target,231std::string &output, Status &error) override;232233bool RunScriptFormatKeyword(const char *impl_function, StackFrame *frame,234std::string &output, Status &error) override;235236bool RunScriptFormatKeyword(const char *impl_function, ValueObject *value,237std::string &output, Status &error) override;238239bool LoadScriptingModule(const char *filename,240const LoadScriptOptions &options,241lldb_private::Status &error,242StructuredData::ObjectSP *module_sp = nullptr,243FileSpec extra_search_dir = {}) override;244245bool IsReservedWord(const char *word) override;246247std::unique_ptr<ScriptInterpreterLocker> AcquireInterpreterLock() override;248249void CollectDataForBreakpointCommandCallback(250std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,251CommandReturnObject &result) override;252253void254CollectDataForWatchpointCommandCallback(WatchpointOptions *wp_options,255CommandReturnObject &result) override;256257/// Set the callback body text into the callback for the breakpoint.258Status SetBreakpointCommandCallback(BreakpointOptions &bp_options,259const char *callback_body,260bool is_callback) override;261262Status SetBreakpointCommandCallbackFunction(263BreakpointOptions &bp_options, const char *function_name,264StructuredData::ObjectSP extra_args_sp) override;265266/// This one is for deserialization:267Status SetBreakpointCommandCallback(268BreakpointOptions &bp_options,269std::unique_ptr<BreakpointOptions::CommandData> &data_up) override;270271Status SetBreakpointCommandCallback(BreakpointOptions &bp_options,272const char *command_body_text,273StructuredData::ObjectSP extra_args_sp,274bool uses_extra_args,275bool is_callback);276277/// Set a one-liner as the callback for the watchpoint.278void SetWatchpointCommandCallback(WatchpointOptions *wp_options,279const char *user_input,280bool is_callback) override;281282const char *GetDictionaryName() { return m_dictionary_name.c_str(); }283284PyThreadState *GetThreadState() { return m_command_thread_state; }285286void SetThreadState(PyThreadState *s) {287if (s)288m_command_thread_state = s;289}290291// IOHandlerDelegate292void IOHandlerActivated(IOHandler &io_handler, bool interactive) override;293294void IOHandlerInputComplete(IOHandler &io_handler,295std::string &data) override;296297static lldb::ScriptInterpreterSP CreateInstance(Debugger &debugger);298299// PluginInterface protocol300llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }301302class Locker : public ScriptInterpreterLocker {303public:304enum OnEntry {305AcquireLock = 0x0001,306InitSession = 0x0002,307InitGlobals = 0x0004,308NoSTDIN = 0x0008309};310311enum OnLeave {312FreeLock = 0x0001,313FreeAcquiredLock = 0x0002, // do not free the lock if we already held it314// when calling constructor315TearDownSession = 0x0004316};317318Locker(ScriptInterpreterPythonImpl *py_interpreter,319uint16_t on_entry = AcquireLock | InitSession,320uint16_t on_leave = FreeLock | TearDownSession,321lldb::FileSP in = nullptr, lldb::FileSP out = nullptr,322lldb::FileSP err = nullptr);323324~Locker() override;325326private:327bool DoAcquireLock();328329bool DoInitSession(uint16_t on_entry_flags, lldb::FileSP in,330lldb::FileSP out, lldb::FileSP err);331332bool DoFreeLock();333334bool DoTearDownSession();335336bool m_teardown_session;337ScriptInterpreterPythonImpl *m_python_interpreter;338PyGILState_STATE m_GILState;339};340341static bool BreakpointCallbackFunction(void *baton,342StoppointCallbackContext *context,343lldb::user_id_t break_id,344lldb::user_id_t break_loc_id);345static bool WatchpointCallbackFunction(void *baton,346StoppointCallbackContext *context,347lldb::user_id_t watch_id);348static void Initialize();349350class SynchronicityHandler {351private:352lldb::DebuggerSP m_debugger_sp;353ScriptedCommandSynchronicity m_synch_wanted;354bool m_old_asynch;355356public:357SynchronicityHandler(lldb::DebuggerSP, ScriptedCommandSynchronicity);358359~SynchronicityHandler();360};361362enum class AddLocation { Beginning, End };363364static void AddToSysPath(AddLocation location, std::string path);365366bool EnterSession(uint16_t on_entry_flags, lldb::FileSP in, lldb::FileSP out,367lldb::FileSP err);368369void LeaveSession();370371uint32_t IsExecutingPython() {372std::lock_guard<std::mutex> guard(m_mutex);373return m_lock_count > 0;374}375376uint32_t IncrementLockCount() {377std::lock_guard<std::mutex> guard(m_mutex);378return ++m_lock_count;379}380381uint32_t DecrementLockCount() {382std::lock_guard<std::mutex> guard(m_mutex);383if (m_lock_count > 0)384--m_lock_count;385return m_lock_count;386}387388enum ActiveIOHandler {389eIOHandlerNone,390eIOHandlerBreakpoint,391eIOHandlerWatchpoint392};393394python::PythonModule &GetMainModule();395396python::PythonDictionary &GetSessionDictionary();397398python::PythonDictionary &GetSysModuleDictionary();399400llvm::Expected<unsigned> GetMaxPositionalArgumentsForCallable(401const llvm::StringRef &callable_name) override;402403bool GetEmbeddedInterpreterModuleObjects();404405bool SetStdHandle(lldb::FileSP file, const char *py_name,406python::PythonObject &save_file, const char *mode);407408python::PythonObject m_saved_stdin;409python::PythonObject m_saved_stdout;410python::PythonObject m_saved_stderr;411python::PythonModule m_main_module;412python::PythonDictionary m_session_dict;413python::PythonDictionary m_sys_module_dict;414python::PythonObject m_run_one_line_function;415python::PythonObject m_run_one_line_str_global;416std::string m_dictionary_name;417ActiveIOHandler m_active_io_handler;418bool m_session_is_active;419bool m_pty_secondary_is_open;420bool m_valid_session;421uint32_t m_lock_count;422std::mutex m_mutex;423PyThreadState *m_command_thread_state;424};425426class IOHandlerPythonInterpreter : public IOHandler {427public:428IOHandlerPythonInterpreter(Debugger &debugger,429ScriptInterpreterPythonImpl *python)430: IOHandler(debugger, IOHandler::Type::PythonInterpreter),431m_python(python) {}432433~IOHandlerPythonInterpreter() override = default;434435llvm::StringRef GetControlSequence(char ch) override {436static constexpr llvm::StringLiteral control_sequence("quit()\n");437if (ch == 'd')438return control_sequence;439return {};440}441442void Run() override {443if (m_python) {444int stdin_fd = GetInputFD();445if (stdin_fd >= 0) {446Terminal terminal(stdin_fd);447TerminalState terminal_state(terminal);448449if (terminal.IsATerminal()) {450// FIXME: error handling?451llvm::consumeError(terminal.SetCanonical(false));452llvm::consumeError(terminal.SetEcho(true));453}454455ScriptInterpreterPythonImpl::Locker locker(456m_python,457ScriptInterpreterPythonImpl::Locker::AcquireLock |458ScriptInterpreterPythonImpl::Locker::InitSession |459ScriptInterpreterPythonImpl::Locker::InitGlobals,460ScriptInterpreterPythonImpl::Locker::FreeAcquiredLock |461ScriptInterpreterPythonImpl::Locker::TearDownSession);462463// The following call drops into the embedded interpreter loop and464// stays there until the user chooses to exit from the Python465// interpreter. This embedded interpreter will, as any Python code that466// performs I/O, unlock the GIL before a system call that can hang, and467// lock it when the syscall has returned.468469// We need to surround the call to the embedded interpreter with calls470// to PyGILState_Ensure and PyGILState_Release (using the Locker471// above). This is because Python has a global lock which must be held472// whenever we want to touch any Python objects. Otherwise, if the user473// calls Python code, the interpreter state will be off, and things474// could hang (it's happened before).475476StreamString run_string;477run_string.Printf("run_python_interpreter (%s)",478m_python->GetDictionaryName());479PyRun_SimpleString(run_string.GetData());480}481}482SetIsDone(true);483}484485void Cancel() override {}486487bool Interrupt() override { return m_python->Interrupt(); }488489void GotEOF() override {}490491protected:492ScriptInterpreterPythonImpl *m_python;493};494495} // namespace lldb_private496497#endif // LLDB_ENABLE_PYTHON498#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTINTERPRETERPYTHONIMPL_H499500501