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