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