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