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
27namespace lldb_private {
28class IOHandlerPythonInterpreter;
29class ScriptInterpreterPythonImpl : public ScriptInterpreterPython {
30public:
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 has_extra_args,
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 extra_search_dir = {},
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 extra_args_sp) 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 extra_args_sp,
281 bool uses_extra_args,
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
433class IOHandlerPythonInterpreter : public IOHandler {
434public:
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
498protected:
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

source code of lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h