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