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