1  //===-- ScriptInterpreterPythonImpl.h ---------------------------*- C++ -*-===//
2  //
3  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4  // See https://llvm.org/LICENSE.txt for license information.
5  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6  //
7  //===----------------------------------------------------------------------===//
8  
9  #ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTINTERPRETERPYTHONIMPL_H
10  #define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTINTERPRETERPYTHONIMPL_H
11  
12  #include "lldb/Host/Config.h"
13  
14  #if LLDB_ENABLE_PYTHON
15  
16  #include "lldb-python.h"
17  
18  #include "PythonDataObjects.h"
19  #include "ScriptInterpreterPython.h"
20  
21  #include "lldb/Host/Terminal.h"
22  #include "lldb/Utility/StreamString.h"
23  
24  #include "llvm/ADT/STLExtras.h"
25  #include "llvm/ADT/StringRef.h"
26  
27  namespace lldb_private {
28  class IOHandlerPythonInterpreter;
29  class ScriptInterpreterPythonImpl : public ScriptInterpreterPython {
30  public:
31    friend class IOHandlerPythonInterpreter;
32  
33    ScriptInterpreterPythonImpl(Debugger &debugger);
34  
35    ~ScriptInterpreterPythonImpl() override;
36  
37    bool Interrupt() override;
38  
39    bool ExecuteOneLine(
40        llvm::StringRef command, CommandReturnObject *result,
41        const ExecuteScriptOptions &options = ExecuteScriptOptions()) override;
42  
43    void ExecuteInterpreterLoop() override;
44  
45    bool ExecuteOneLineWithReturn(
46        llvm::StringRef in_string,
47        ScriptInterpreter::ScriptReturnType return_type, void *ret_value,
48        const ExecuteScriptOptions &options = ExecuteScriptOptions()) override;
49  
50    lldb_private::Status ExecuteMultipleLines(
51        const char *in_string,
52        const ExecuteScriptOptions &options = ExecuteScriptOptions()) override;
53  
54    Status
55    ExportFunctionDefinitionToInterpreter(StringList &function_def) override;
56  
57    bool GenerateTypeScriptFunction(StringList &input, std::string &output,
58                                    const void *name_token = nullptr) override;
59  
60    bool GenerateTypeSynthClass(StringList &input, std::string &output,
61                                const void *name_token = nullptr) override;
62  
63    bool GenerateTypeSynthClass(const char *oneliner, std::string &output,
64                                const void *name_token = nullptr) override;
65  
66    // use this if the function code is just a one-liner script
67    bool GenerateTypeScriptFunction(const char *oneliner, std::string &output,
68                                    const void *name_token = nullptr) override;
69  
70    bool GenerateScriptAliasFunction(StringList &input,
71                                     std::string &output) override;
72  
73    StructuredData::ObjectSP
74    CreateSyntheticScriptedProvider(const char *class_name,
75                                    lldb::ValueObjectSP valobj) override;
76  
77    StructuredData::GenericSP
78    CreateScriptCommandObject(const char *class_name) override;
79  
80    StructuredData::ObjectSP
81    CreateStructuredDataFromScriptObject(ScriptObject obj) override;
82  
83    StructuredData::GenericSP
84    CreateScriptedBreakpointResolver(const char *class_name,
85                                     const StructuredDataImpl &args_data,
86                                     lldb::BreakpointSP &bkpt_sp) override;
87    bool ScriptedBreakpointResolverSearchCallback(
88        StructuredData::GenericSP implementor_sp,
89        SymbolContext *sym_ctx) override;
90  
91    lldb::SearchDepth ScriptedBreakpointResolverSearchDepth(
92        StructuredData::GenericSP implementor_sp) override;
93  
94    StructuredData::GenericSP
95    CreateScriptedStopHook(lldb::TargetSP target_sp, const char *class_name,
96                           const StructuredDataImpl &args_data,
97                           Status &error) override;
98  
99    bool ScriptedStopHookHandleStop(StructuredData::GenericSP implementor_sp,
100                                    ExecutionContext &exc_ctx,
101                                    lldb::StreamSP stream_sp) override;
102  
103    StructuredData::GenericSP
104    CreateFrameRecognizer(const char *class_name) override;
105  
106    lldb::ValueObjectListSP
107    GetRecognizedArguments(const StructuredData::ObjectSP &implementor,
108                           lldb::StackFrameSP frame_sp) override;
109  
110    lldb::ScriptedProcessInterfaceUP CreateScriptedProcessInterface() override;
111  
112    lldb::ScriptedThreadInterfaceSP CreateScriptedThreadInterface() override;
113  
114    lldb::ScriptedThreadPlanInterfaceSP
115    CreateScriptedThreadPlanInterface() override;
116  
117    lldb::OperatingSystemInterfaceSP CreateOperatingSystemInterface() override;
118  
119    StructuredData::ObjectSP
120    LoadPluginModule(const FileSpec &file_spec,
121                     lldb_private::Status &error) override;
122  
123    StructuredData::DictionarySP
124    GetDynamicSettings(StructuredData::ObjectSP plugin_module_sp, Target *target,
125                       const char *setting_name,
126                       lldb_private::Status &error) override;
127  
128    size_t CalculateNumChildren(const StructuredData::ObjectSP &implementor,
129                                uint32_t max) override;
130  
131    lldb::ValueObjectSP
132    GetChildAtIndex(const StructuredData::ObjectSP &implementor,
133                    uint32_t idx) override;
134  
135    int GetIndexOfChildWithName(const StructuredData::ObjectSP &implementor,
136                                const char *child_name) override;
137  
138    bool UpdateSynthProviderInstance(
139        const StructuredData::ObjectSP &implementor) override;
140  
141    bool MightHaveChildrenSynthProviderInstance(
142        const StructuredData::ObjectSP &implementor) override;
143  
144    lldb::ValueObjectSP
145    GetSyntheticValue(const StructuredData::ObjectSP &implementor) override;
146  
147    ConstString
148    GetSyntheticTypeName(const StructuredData::ObjectSP &implementor) override;
149  
150    bool
151    RunScriptBasedCommand(const char *impl_function, llvm::StringRef args,
152                          ScriptedCommandSynchronicity synchronicity,
153                          lldb_private::CommandReturnObject &cmd_retobj,
154                          Status &error,
155                          const lldb_private::ExecutionContext &exe_ctx) override;
156  
157    bool RunScriptBasedCommand(
158        StructuredData::GenericSP impl_obj_sp, llvm::StringRef args,
159        ScriptedCommandSynchronicity synchronicity,
160        lldb_private::CommandReturnObject &cmd_retobj, Status &error,
161        const lldb_private::ExecutionContext &exe_ctx) override;
162  
163    bool RunScriptBasedParsedCommand(
164        StructuredData::GenericSP impl_obj_sp, Args &args,
165        ScriptedCommandSynchronicity synchronicity,
166        lldb_private::CommandReturnObject &cmd_retobj, Status &error,
167        const lldb_private::ExecutionContext &exe_ctx) override;
168  
169    std::optional<std::string>
170    GetRepeatCommandForScriptedCommand(StructuredData::GenericSP impl_obj_sp,
171                                       Args &args) override;
172  
173    Status GenerateFunction(const char *signature, const StringList &input,
174                            bool is_callback) override;
175  
176    Status GenerateBreakpointCommandCallbackData(StringList &input,
177                                                 std::string &output,
178                                                 bool has_extra_args,
179                                                 bool is_callback) override;
180  
181    bool GenerateWatchpointCommandCallbackData(StringList &input,
182                                               std::string &output,
183                                               bool is_callback) override;
184  
185    bool GetScriptedSummary(const char *function_name, lldb::ValueObjectSP valobj,
186                            StructuredData::ObjectSP &callee_wrapper_sp,
187                            const TypeSummaryOptions &options,
188                            std::string &retval) override;
189  
190    bool FormatterCallbackFunction(const char *function_name,
191                                   lldb::TypeImplSP type_impl_sp) override;
192  
193    bool GetDocumentationForItem(const char *item, std::string &dest) override;
194  
195    bool GetShortHelpForCommandObject(StructuredData::GenericSP cmd_obj_sp,
196                                      std::string &dest) override;
197  
198    uint32_t
199    GetFlagsForCommandObject(StructuredData::GenericSP cmd_obj_sp) override;
200  
201    bool GetLongHelpForCommandObject(StructuredData::GenericSP cmd_obj_sp,
202                                     std::string &dest) override;
203  
204    StructuredData::ObjectSP
205    GetOptionsForCommandObject(StructuredData::GenericSP cmd_obj_sp) override;
206  
207    StructuredData::ObjectSP
208    GetArgumentsForCommandObject(StructuredData::GenericSP cmd_obj_sp) override;
209  
210    bool SetOptionValueForCommandObject(StructuredData::GenericSP cmd_obj_sp,
211                                        ExecutionContext *exe_ctx,
212                                        llvm::StringRef long_option,
213                                        llvm::StringRef value) override;
214  
215    void OptionParsingStartedForCommandObject(
216        StructuredData::GenericSP cmd_obj_sp) override;
217  
CheckObjectExists(const char * name)218    bool CheckObjectExists(const char *name) override {
219      if (!name || !name[0])
220        return false;
221      std::string temp;
222      return GetDocumentationForItem(name, temp);
223    }
224  
225    bool RunScriptFormatKeyword(const char *impl_function, Process *process,
226                                std::string &output, Status &error) override;
227  
228    bool RunScriptFormatKeyword(const char *impl_function, Thread *thread,
229                                std::string &output, Status &error) override;
230  
231    bool RunScriptFormatKeyword(const char *impl_function, Target *target,
232                                std::string &output, Status &error) override;
233  
234    bool RunScriptFormatKeyword(const char *impl_function, StackFrame *frame,
235                                std::string &output, Status &error) override;
236  
237    bool RunScriptFormatKeyword(const char *impl_function, ValueObject *value,
238                                std::string &output, Status &error) override;
239  
240    bool LoadScriptingModule(const char *filename,
241                             const LoadScriptOptions &options,
242                             lldb_private::Status &error,
243                             StructuredData::ObjectSP *module_sp = nullptr,
244                             FileSpec extra_search_dir = {}) override;
245  
246    bool IsReservedWord(const char *word) override;
247  
248    std::unique_ptr<ScriptInterpreterLocker> AcquireInterpreterLock() override;
249  
250    void CollectDataForBreakpointCommandCallback(
251        std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
252        CommandReturnObject &result) override;
253  
254    void
255    CollectDataForWatchpointCommandCallback(WatchpointOptions *wp_options,
256                                            CommandReturnObject &result) override;
257  
258    /// Set the callback body text into the callback for the breakpoint.
259    Status SetBreakpointCommandCallback(BreakpointOptions &bp_options,
260                                        const char *callback_body,
261                                        bool is_callback) override;
262  
263    Status SetBreakpointCommandCallbackFunction(
264        BreakpointOptions &bp_options, const char *function_name,
265        StructuredData::ObjectSP extra_args_sp) override;
266  
267    /// This one is for deserialization:
268    Status SetBreakpointCommandCallback(
269        BreakpointOptions &bp_options,
270        std::unique_ptr<BreakpointOptions::CommandData> &data_up) override;
271  
272    Status SetBreakpointCommandCallback(BreakpointOptions &bp_options,
273                                        const char *command_body_text,
274                                        StructuredData::ObjectSP extra_args_sp,
275                                        bool uses_extra_args,
276                                        bool is_callback);
277  
278    /// Set a one-liner as the callback for the watchpoint.
279    void SetWatchpointCommandCallback(WatchpointOptions *wp_options,
280                                      const char *user_input,
281                                      bool is_callback) override;
282  
GetDictionaryName()283    const char *GetDictionaryName() { return m_dictionary_name.c_str(); }
284  
GetThreadState()285    PyThreadState *GetThreadState() { return m_command_thread_state; }
286  
SetThreadState(PyThreadState * s)287    void SetThreadState(PyThreadState *s) {
288      if (s)
289        m_command_thread_state = s;
290    }
291  
292    // IOHandlerDelegate
293    void IOHandlerActivated(IOHandler &io_handler, bool interactive) override;
294  
295    void IOHandlerInputComplete(IOHandler &io_handler,
296                                std::string &data) override;
297  
298    static lldb::ScriptInterpreterSP CreateInstance(Debugger &debugger);
299  
300    // PluginInterface protocol
GetPluginName()301    llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
302  
303    class Locker : public ScriptInterpreterLocker {
304    public:
305      enum OnEntry {
306        AcquireLock = 0x0001,
307        InitSession = 0x0002,
308        InitGlobals = 0x0004,
309        NoSTDIN = 0x0008
310      };
311  
312      enum OnLeave {
313        FreeLock = 0x0001,
314        FreeAcquiredLock = 0x0002, // do not free the lock if we already held it
315                                   // when calling constructor
316        TearDownSession = 0x0004
317      };
318  
319      Locker(ScriptInterpreterPythonImpl *py_interpreter,
320             uint16_t on_entry = AcquireLock | InitSession,
321             uint16_t on_leave = FreeLock | TearDownSession,
322             lldb::FileSP in = nullptr, lldb::FileSP out = nullptr,
323             lldb::FileSP err = nullptr);
324  
325      ~Locker() override;
326  
327    private:
328      bool DoAcquireLock();
329  
330      bool DoInitSession(uint16_t on_entry_flags, lldb::FileSP in,
331                         lldb::FileSP out, lldb::FileSP err);
332  
333      bool DoFreeLock();
334  
335      bool DoTearDownSession();
336  
337      bool m_teardown_session;
338      ScriptInterpreterPythonImpl *m_python_interpreter;
339      PyGILState_STATE m_GILState;
340    };
341  
342    static bool BreakpointCallbackFunction(void *baton,
343                                           StoppointCallbackContext *context,
344                                           lldb::user_id_t break_id,
345                                           lldb::user_id_t break_loc_id);
346    static bool WatchpointCallbackFunction(void *baton,
347                                           StoppointCallbackContext *context,
348                                           lldb::user_id_t watch_id);
349    static void Initialize();
350  
351    class SynchronicityHandler {
352    private:
353      lldb::DebuggerSP m_debugger_sp;
354      ScriptedCommandSynchronicity m_synch_wanted;
355      bool m_old_asynch;
356  
357    public:
358      SynchronicityHandler(lldb::DebuggerSP, ScriptedCommandSynchronicity);
359  
360      ~SynchronicityHandler();
361    };
362  
363    enum class AddLocation { Beginning, End };
364  
365    static void AddToSysPath(AddLocation location, std::string path);
366  
367    bool EnterSession(uint16_t on_entry_flags, lldb::FileSP in, lldb::FileSP out,
368                      lldb::FileSP err);
369  
370    void LeaveSession();
371  
IsExecutingPython()372    uint32_t IsExecutingPython() {
373      std::lock_guard<std::mutex> guard(m_mutex);
374      return m_lock_count > 0;
375    }
376  
IncrementLockCount()377    uint32_t IncrementLockCount() {
378      std::lock_guard<std::mutex> guard(m_mutex);
379      return ++m_lock_count;
380    }
381  
DecrementLockCount()382    uint32_t DecrementLockCount() {
383      std::lock_guard<std::mutex> guard(m_mutex);
384      if (m_lock_count > 0)
385        --m_lock_count;
386      return m_lock_count;
387    }
388  
389    enum ActiveIOHandler {
390      eIOHandlerNone,
391      eIOHandlerBreakpoint,
392      eIOHandlerWatchpoint
393    };
394  
395    python::PythonModule &GetMainModule();
396  
397    python::PythonDictionary &GetSessionDictionary();
398  
399    python::PythonDictionary &GetSysModuleDictionary();
400  
401    llvm::Expected<unsigned> GetMaxPositionalArgumentsForCallable(
402        const llvm::StringRef &callable_name) override;
403  
404    bool GetEmbeddedInterpreterModuleObjects();
405  
406    bool SetStdHandle(lldb::FileSP file, const char *py_name,
407                      python::PythonObject &save_file, const char *mode);
408  
409    python::PythonObject m_saved_stdin;
410    python::PythonObject m_saved_stdout;
411    python::PythonObject m_saved_stderr;
412    python::PythonModule m_main_module;
413    python::PythonDictionary m_session_dict;
414    python::PythonDictionary m_sys_module_dict;
415    python::PythonObject m_run_one_line_function;
416    python::PythonObject m_run_one_line_str_global;
417    std::string m_dictionary_name;
418    ActiveIOHandler m_active_io_handler;
419    bool m_session_is_active;
420    bool m_pty_secondary_is_open;
421    bool m_valid_session;
422    uint32_t m_lock_count;
423    std::mutex m_mutex;
424    PyThreadState *m_command_thread_state;
425  };
426  
427  class IOHandlerPythonInterpreter : public IOHandler {
428  public:
IOHandlerPythonInterpreter(Debugger & debugger,ScriptInterpreterPythonImpl * python)429    IOHandlerPythonInterpreter(Debugger &debugger,
430                               ScriptInterpreterPythonImpl *python)
431        : IOHandler(debugger, IOHandler::Type::PythonInterpreter),
432          m_python(python) {}
433  
434    ~IOHandlerPythonInterpreter() override = default;
435  
GetControlSequence(char ch)436    llvm::StringRef GetControlSequence(char ch) override {
437      static constexpr llvm::StringLiteral control_sequence("quit()\n");
438      if (ch == 'd')
439        return control_sequence;
440      return {};
441    }
442  
Run()443    void Run() override {
444      if (m_python) {
445        int stdin_fd = GetInputFD();
446        if (stdin_fd >= 0) {
447          Terminal terminal(stdin_fd);
448          TerminalState terminal_state(terminal);
449  
450          if (terminal.IsATerminal()) {
451            // FIXME: error handling?
452            llvm::consumeError(terminal.SetCanonical(false));
453            llvm::consumeError(terminal.SetEcho(true));
454          }
455  
456          ScriptInterpreterPythonImpl::Locker locker(
457              m_python,
458              ScriptInterpreterPythonImpl::Locker::AcquireLock |
459                  ScriptInterpreterPythonImpl::Locker::InitSession |
460                  ScriptInterpreterPythonImpl::Locker::InitGlobals,
461              ScriptInterpreterPythonImpl::Locker::FreeAcquiredLock |
462                  ScriptInterpreterPythonImpl::Locker::TearDownSession);
463  
464          // The following call drops into the embedded interpreter loop and
465          // stays there until the user chooses to exit from the Python
466          // interpreter. This embedded interpreter will, as any Python code that
467          // performs I/O, unlock the GIL before a system call that can hang, and
468          // lock it when the syscall has returned.
469  
470          // We need to surround the call to the embedded interpreter with calls
471          // to PyGILState_Ensure and PyGILState_Release (using the Locker
472          // above). This is because Python has a global lock which must be held
473          // whenever we want to touch any Python objects. Otherwise, if the user
474          // calls Python code, the interpreter state will be off, and things
475          // could hang (it's happened before).
476  
477          StreamString run_string;
478          run_string.Printf("run_python_interpreter (%s)",
479                            m_python->GetDictionaryName());
480          PyRun_SimpleString(run_string.GetData());
481        }
482      }
483      SetIsDone(true);
484    }
485  
Cancel()486    void Cancel() override {}
487  
Interrupt()488    bool Interrupt() override { return m_python->Interrupt(); }
489  
GotEOF()490    void GotEOF() override {}
491  
492  protected:
493    ScriptInterpreterPythonImpl *m_python;
494  };
495  
496  } // namespace lldb_private
497  
498  #endif // LLDB_ENABLE_PYTHON
499  #endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTINTERPRETERPYTHONIMPL_H
500