1 | //===-- ScriptInterpreterPython.cpp ---------------------------------------===// |
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 | #include "lldb/Host/Config.h" |
10 | |
11 | #if LLDB_ENABLE_PYTHON |
12 | |
13 | // LLDB Python header must be included first |
14 | #include "lldb-python.h" |
15 | |
16 | #include "Interfaces/ScriptInterpreterPythonInterfaces.h" |
17 | #include "PythonDataObjects.h" |
18 | #include "PythonReadline.h" |
19 | #include "SWIGPythonBridge.h" |
20 | #include "ScriptInterpreterPythonImpl.h" |
21 | |
22 | #include "lldb/API/SBError.h" |
23 | #include "lldb/API/SBExecutionContext.h" |
24 | #include "lldb/API/SBFrame.h" |
25 | #include "lldb/API/SBValue.h" |
26 | #include "lldb/Breakpoint/StoppointCallbackContext.h" |
27 | #include "lldb/Breakpoint/WatchpointOptions.h" |
28 | #include "lldb/Core/Debugger.h" |
29 | #include "lldb/Core/PluginManager.h" |
30 | #include "lldb/Core/ThreadedCommunication.h" |
31 | #include "lldb/DataFormatters/TypeSummary.h" |
32 | #include "lldb/Host/FileSystem.h" |
33 | #include "lldb/Host/HostInfo.h" |
34 | #include "lldb/Host/Pipe.h" |
35 | #include "lldb/Host/StreamFile.h" |
36 | #include "lldb/Interpreter/CommandInterpreter.h" |
37 | #include "lldb/Interpreter/CommandReturnObject.h" |
38 | #include "lldb/Target/Thread.h" |
39 | #include "lldb/Target/ThreadPlan.h" |
40 | #include "lldb/Utility/Instrumentation.h" |
41 | #include "lldb/Utility/LLDBLog.h" |
42 | #include "lldb/Utility/Timer.h" |
43 | #include "lldb/ValueObject/ValueObject.h" |
44 | #include "lldb/lldb-enumerations.h" |
45 | #include "lldb/lldb-forward.h" |
46 | #include "llvm/ADT/STLExtras.h" |
47 | #include "llvm/ADT/StringRef.h" |
48 | #include "llvm/Support/Error.h" |
49 | #include "llvm/Support/FileSystem.h" |
50 | #include "llvm/Support/FormatAdapters.h" |
51 | |
52 | #include <cstdio> |
53 | #include <cstdlib> |
54 | #include <memory> |
55 | #include <mutex> |
56 | #include <optional> |
57 | #include <string> |
58 | |
59 | using namespace lldb; |
60 | using namespace lldb_private; |
61 | using namespace lldb_private::python; |
62 | using llvm::Expected; |
63 | |
64 | LLDB_PLUGIN_DEFINE(ScriptInterpreterPython) |
65 | |
66 | // Defined in the SWIG source file |
67 | extern "C" PyObject *PyInit__lldb(void); |
68 | |
69 | #define LLDBSwigPyInit PyInit__lldb |
70 | |
71 | #if defined(_WIN32) |
72 | // Don't mess with the signal handlers on Windows. |
73 | #define LLDB_USE_PYTHON_SET_INTERRUPT 0 |
74 | #else |
75 | #define LLDB_USE_PYTHON_SET_INTERRUPT 1 |
76 | #endif |
77 | |
78 | static ScriptInterpreterPythonImpl *GetPythonInterpreter(Debugger &debugger) { |
79 | ScriptInterpreter *script_interpreter = |
80 | debugger.GetScriptInterpreter(can_create: true, language: lldb::eScriptLanguagePython); |
81 | return static_cast<ScriptInterpreterPythonImpl *>(script_interpreter); |
82 | } |
83 | |
84 | namespace { |
85 | |
86 | // Initializing Python is not a straightforward process. We cannot control |
87 | // what external code may have done before getting to this point in LLDB, |
88 | // including potentially having already initialized Python, so we need to do a |
89 | // lot of work to ensure that the existing state of the system is maintained |
90 | // across our initialization. We do this by using an RAII pattern where we |
91 | // save off initial state at the beginning, and restore it at the end |
92 | struct InitializePythonRAII { |
93 | public: |
94 | InitializePythonRAII() { |
95 | PyConfig config; |
96 | PyConfig_InitPythonConfig(config: &config); |
97 | |
98 | #if LLDB_EMBED_PYTHON_HOME |
99 | static std::string g_python_home = []() -> std::string { |
100 | if (llvm::sys::path::is_absolute(LLDB_PYTHON_HOME)) |
101 | return LLDB_PYTHON_HOME; |
102 | |
103 | FileSpec spec = HostInfo::GetShlibDir(); |
104 | if (!spec) |
105 | return {}; |
106 | spec.AppendPathComponent(LLDB_PYTHON_HOME); |
107 | return spec.GetPath(); |
108 | }(); |
109 | if (!g_python_home.empty()) { |
110 | PyConfig_SetBytesString(&config, &config.home, g_python_home.c_str()); |
111 | } |
112 | #endif |
113 | |
114 | // The table of built-in modules can only be extended before Python is |
115 | // initialized. |
116 | if (!Py_IsInitialized()) { |
117 | #ifdef LLDB_USE_LIBEDIT_READLINE_COMPAT_MODULE |
118 | // Python's readline is incompatible with libedit being linked into lldb. |
119 | // Provide a patched version local to the embedded interpreter. |
120 | bool ReadlinePatched = false; |
121 | for (auto *p = PyImport_Inittab; p->name != nullptr; p++) { |
122 | if (strcmp(s1: p->name, s2: "readline" ) == 0) { |
123 | p->initfunc = initlldb_readline; |
124 | break; |
125 | } |
126 | } |
127 | if (!ReadlinePatched) { |
128 | PyImport_AppendInittab(name: "readline" , initfunc: initlldb_readline); |
129 | ReadlinePatched = true; |
130 | } |
131 | #endif |
132 | |
133 | // Register _lldb as a built-in module. |
134 | PyImport_AppendInittab(name: "_lldb" , LLDBSwigPyInit); |
135 | } |
136 | |
137 | config.install_signal_handlers = 0; |
138 | Py_InitializeFromConfig(config: &config); |
139 | PyConfig_Clear(&config); |
140 | InitializeThreadsPrivate(); |
141 | } |
142 | |
143 | ~InitializePythonRAII() { |
144 | if (m_was_already_initialized) { |
145 | Log *log = GetLog(mask: LLDBLog::Script); |
146 | LLDB_LOGV(log, "Releasing PyGILState. Returning to state = {0}locked" , |
147 | m_gil_state == PyGILState_UNLOCKED ? "un" : "" ); |
148 | PyGILState_Release(m_gil_state); |
149 | } else { |
150 | // We initialized the threads in this function, just unlock the GIL. |
151 | PyEval_SaveThread(); |
152 | } |
153 | } |
154 | |
155 | private: |
156 | void InitializeThreadsPrivate() { |
157 | // Since Python 3.7 `Py_Initialize` calls `PyEval_InitThreads` inside |
158 | // itself, so there is no way to determine whether the embedded interpreter |
159 | // was already initialized by some external code. |
160 | // `PyEval_ThreadsInitialized` would always return `true` and |
161 | // `PyGILState_Ensure/Release` flow would be executed instead of unlocking |
162 | // GIL with `PyEval_SaveThread`. When an another thread calls |
163 | // `PyGILState_Ensure` it would get stuck in deadlock. |
164 | |
165 | // The only case we should go further and acquire the GIL: it is unlocked. |
166 | if (PyGILState_Check()) |
167 | return; |
168 | |
169 | // `PyEval_ThreadsInitialized` was deprecated in Python 3.9 and removed in |
170 | // Python 3.13. It has been returning `true` always since Python 3.7. |
171 | #if PY_VERSION_HEX < 0x03090000 |
172 | if (PyEval_ThreadsInitialized()) { |
173 | #else |
174 | if (true) { |
175 | #endif |
176 | Log *log = GetLog(mask: LLDBLog::Script); |
177 | |
178 | m_was_already_initialized = true; |
179 | m_gil_state = PyGILState_Ensure(); |
180 | LLDB_LOGV(log, "Ensured PyGILState. Previous state = {0}locked\n" , |
181 | m_gil_state == PyGILState_UNLOCKED ? "un" : "" ); |
182 | |
183 | // `PyEval_InitThreads` was deprecated in Python 3.9 and removed in |
184 | // Python 3.13. |
185 | #if PY_VERSION_HEX < 0x03090000 |
186 | return; |
187 | } |
188 | |
189 | // InitThreads acquires the GIL if it hasn't been called before. |
190 | PyEval_InitThreads(); |
191 | #else |
192 | } |
193 | #endif |
194 | } |
195 | |
196 | PyGILState_STATE m_gil_state = PyGILState_UNLOCKED; |
197 | bool m_was_already_initialized = false; |
198 | }; |
199 | |
200 | #if LLDB_USE_PYTHON_SET_INTERRUPT |
201 | /// Saves the current signal handler for the specified signal and restores |
202 | /// it at the end of the current scope. |
203 | struct RestoreSignalHandlerScope { |
204 | /// The signal handler. |
205 | struct sigaction m_prev_handler; |
206 | int m_signal_code; |
207 | RestoreSignalHandlerScope(int signal_code) : m_signal_code(signal_code) { |
208 | // Initialize sigaction to their default state. |
209 | std::memset(s: &m_prev_handler, c: 0, n: sizeof(m_prev_handler)); |
210 | // Don't install a new handler, just read back the old one. |
211 | struct sigaction *new_handler = nullptr; |
212 | int signal_err = ::sigaction(sig: m_signal_code, act: new_handler, oact: &m_prev_handler); |
213 | lldbassert(signal_err == 0 && "sigaction failed to read handler" ); |
214 | } |
215 | ~RestoreSignalHandlerScope() { |
216 | int signal_err = ::sigaction(sig: m_signal_code, act: &m_prev_handler, oact: nullptr); |
217 | lldbassert(signal_err == 0 && "sigaction failed to restore old handler" ); |
218 | } |
219 | }; |
220 | #endif |
221 | } // namespace |
222 | |
223 | void ScriptInterpreterPython::ComputePythonDirForApple( |
224 | llvm::SmallVectorImpl<char> &path) { |
225 | auto style = llvm::sys::path::Style::posix; |
226 | |
227 | llvm::StringRef path_ref(path.begin(), path.size()); |
228 | auto rbegin = llvm::sys::path::rbegin(path: path_ref, style); |
229 | auto rend = llvm::sys::path::rend(path: path_ref); |
230 | auto framework = std::find(first: rbegin, last: rend, val: "LLDB.framework" ); |
231 | if (framework == rend) { |
232 | ComputePythonDir(path); |
233 | return; |
234 | } |
235 | path.resize(N: framework - rend); |
236 | llvm::sys::path::append(path, style, a: "LLDB.framework" , b: "Resources" , c: "Python" ); |
237 | } |
238 | |
239 | void ScriptInterpreterPython::ComputePythonDir( |
240 | llvm::SmallVectorImpl<char> &path) { |
241 | // Build the path by backing out of the lib dir, then building with whatever |
242 | // the real python interpreter uses. (e.g. lib for most, lib64 on RHEL |
243 | // x86_64, or bin on Windows). |
244 | llvm::sys::path::remove_filename(path); |
245 | llvm::sys::path::append(path, LLDB_PYTHON_RELATIVE_LIBDIR); |
246 | |
247 | #if defined(_WIN32) |
248 | // This will be injected directly through FileSpec.SetDirectory(), |
249 | // so we need to normalize manually. |
250 | std::replace(path.begin(), path.end(), '\\', '/'); |
251 | #endif |
252 | } |
253 | |
254 | FileSpec ScriptInterpreterPython::GetPythonDir() { |
255 | static FileSpec g_spec = []() { |
256 | FileSpec spec = HostInfo::GetShlibDir(); |
257 | if (!spec) |
258 | return FileSpec(); |
259 | llvm::SmallString<64> path; |
260 | spec.GetPath(path); |
261 | |
262 | #if defined(__APPLE__) |
263 | ComputePythonDirForApple(path); |
264 | #else |
265 | ComputePythonDir(path); |
266 | #endif |
267 | spec.SetDirectory(path); |
268 | return spec; |
269 | }(); |
270 | return g_spec; |
271 | } |
272 | |
273 | static const char GetInterpreterInfoScript[] = R"( |
274 | import os |
275 | import sys |
276 | |
277 | def main(lldb_python_dir, python_exe_relative_path): |
278 | info = { |
279 | "lldb-pythonpath": lldb_python_dir, |
280 | "language": "python", |
281 | "prefix": sys.prefix, |
282 | "executable": os.path.join(sys.prefix, python_exe_relative_path) |
283 | } |
284 | return info |
285 | )" ; |
286 | |
287 | static const char python_exe_relative_path[] = LLDB_PYTHON_EXE_RELATIVE_PATH; |
288 | |
289 | StructuredData::DictionarySP ScriptInterpreterPython::GetInterpreterInfo() { |
290 | GIL gil; |
291 | FileSpec python_dir_spec = GetPythonDir(); |
292 | if (!python_dir_spec) |
293 | return nullptr; |
294 | PythonScript get_info(GetInterpreterInfoScript); |
295 | auto info_json = unwrapIgnoringErrors( |
296 | expected: As<PythonDictionary>(obj: get_info(PythonString(python_dir_spec.GetPath()), |
297 | PythonString(python_exe_relative_path)))); |
298 | if (!info_json) |
299 | return nullptr; |
300 | return info_json.CreateStructuredDictionary(); |
301 | } |
302 | |
303 | void ScriptInterpreterPython::SharedLibraryDirectoryHelper( |
304 | FileSpec &this_file) { |
305 | // When we're loaded from python, this_file will point to the file inside the |
306 | // python package directory. Replace it with the one in the lib directory. |
307 | #ifdef _WIN32 |
308 | // On windows, we need to manually back out of the python tree, and go into |
309 | // the bin directory. This is pretty much the inverse of what ComputePythonDir |
310 | // does. |
311 | if (this_file.GetFileNameExtension() == ".pyd" ) { |
312 | this_file.RemoveLastPathComponent(); // _lldb.pyd or _lldb_d.pyd |
313 | this_file.RemoveLastPathComponent(); // lldb |
314 | llvm::StringRef libdir = LLDB_PYTHON_RELATIVE_LIBDIR; |
315 | for (auto it = llvm::sys::path::begin(libdir), |
316 | end = llvm::sys::path::end(libdir); |
317 | it != end; ++it) |
318 | this_file.RemoveLastPathComponent(); |
319 | this_file.AppendPathComponent("bin" ); |
320 | this_file.AppendPathComponent("liblldb.dll" ); |
321 | } |
322 | #else |
323 | // The python file is a symlink, so we can find the real library by resolving |
324 | // it. We can do this unconditionally. |
325 | FileSystem::Instance().ResolveSymbolicLink(src: this_file, dst&: this_file); |
326 | #endif |
327 | } |
328 | |
329 | llvm::StringRef ScriptInterpreterPython::GetPluginDescriptionStatic() { |
330 | return "Embedded Python interpreter" ; |
331 | } |
332 | |
333 | void ScriptInterpreterPython::Initialize() { |
334 | static llvm::once_flag g_once_flag; |
335 | llvm::call_once(flag&: g_once_flag, F: []() { |
336 | PluginManager::RegisterPlugin(name: GetPluginNameStatic(), |
337 | description: GetPluginDescriptionStatic(), |
338 | script_lang: lldb::eScriptLanguagePython, |
339 | create_callback: ScriptInterpreterPythonImpl::CreateInstance); |
340 | ScriptInterpreterPythonImpl::Initialize(); |
341 | }); |
342 | } |
343 | |
344 | void ScriptInterpreterPython::Terminate() {} |
345 | |
346 | ScriptInterpreterPythonImpl::Locker::Locker( |
347 | ScriptInterpreterPythonImpl *py_interpreter, uint16_t on_entry, |
348 | uint16_t on_leave, FileSP in, FileSP out, FileSP err) |
349 | : ScriptInterpreterLocker(), |
350 | m_teardown_session((on_leave & TearDownSession) == TearDownSession), |
351 | m_python_interpreter(py_interpreter) { |
352 | DoAcquireLock(); |
353 | if ((on_entry & InitSession) == InitSession) { |
354 | if (!DoInitSession(on_entry_flags: on_entry, in, out, err)) { |
355 | // Don't teardown the session if we didn't init it. |
356 | m_teardown_session = false; |
357 | } |
358 | } |
359 | } |
360 | |
361 | bool ScriptInterpreterPythonImpl::Locker::DoAcquireLock() { |
362 | Log *log = GetLog(mask: LLDBLog::Script); |
363 | m_GILState = PyGILState_Ensure(); |
364 | LLDB_LOGV(log, "Ensured PyGILState. Previous state = {0}locked" , |
365 | m_GILState == PyGILState_UNLOCKED ? "un" : "" ); |
366 | |
367 | // we need to save the thread state when we first start the command because |
368 | // we might decide to interrupt it while some action is taking place outside |
369 | // of Python (e.g. printing to screen, waiting for the network, ...) in that |
370 | // case, _PyThreadState_Current will be NULL - and we would be unable to set |
371 | // the asynchronous exception - not a desirable situation |
372 | m_python_interpreter->SetThreadState(PyThreadState_Get()); |
373 | m_python_interpreter->IncrementLockCount(); |
374 | return true; |
375 | } |
376 | |
377 | bool ScriptInterpreterPythonImpl::Locker::DoInitSession(uint16_t on_entry_flags, |
378 | FileSP in, FileSP out, |
379 | FileSP err) { |
380 | if (!m_python_interpreter) |
381 | return false; |
382 | return m_python_interpreter->EnterSession(on_entry_flags, in, out, err); |
383 | } |
384 | |
385 | bool ScriptInterpreterPythonImpl::Locker::DoFreeLock() { |
386 | Log *log = GetLog(mask: LLDBLog::Script); |
387 | LLDB_LOGV(log, "Releasing PyGILState. Returning to state = {0}locked" , |
388 | m_GILState == PyGILState_UNLOCKED ? "un" : "" ); |
389 | PyGILState_Release(m_GILState); |
390 | m_python_interpreter->DecrementLockCount(); |
391 | return true; |
392 | } |
393 | |
394 | bool ScriptInterpreterPythonImpl::Locker::DoTearDownSession() { |
395 | if (!m_python_interpreter) |
396 | return false; |
397 | m_python_interpreter->LeaveSession(); |
398 | return true; |
399 | } |
400 | |
401 | ScriptInterpreterPythonImpl::Locker::~Locker() { |
402 | if (m_teardown_session) |
403 | DoTearDownSession(); |
404 | DoFreeLock(); |
405 | } |
406 | |
407 | ScriptInterpreterPythonImpl::ScriptInterpreterPythonImpl(Debugger &debugger) |
408 | : ScriptInterpreterPython(debugger), m_saved_stdin(), m_saved_stdout(), |
409 | m_saved_stderr(), m_main_module(), |
410 | m_session_dict(PyInitialValue::Invalid), |
411 | m_sys_module_dict(PyInitialValue::Invalid), m_run_one_line_function(), |
412 | m_run_one_line_str_global(), |
413 | m_dictionary_name(m_debugger.GetInstanceName()), |
414 | m_active_io_handler(eIOHandlerNone), m_session_is_active(false), |
415 | m_pty_secondary_is_open(false), m_valid_session(true), m_lock_count(0), |
416 | m_command_thread_state(nullptr) { |
417 | |
418 | m_dictionary_name.append(s: "_dict" ); |
419 | StreamString run_string; |
420 | run_string.Printf(format: "%s = dict()" , m_dictionary_name.c_str()); |
421 | |
422 | Locker locker(this, Locker::AcquireLock, Locker::FreeAcquiredLock); |
423 | PyRun_SimpleString(run_string.GetData()); |
424 | |
425 | run_string.Clear(); |
426 | run_string.Printf( |
427 | format: "run_one_line (%s, 'import copy, keyword, os, re, sys, uuid, lldb')" , |
428 | m_dictionary_name.c_str()); |
429 | PyRun_SimpleString(run_string.GetData()); |
430 | |
431 | // Reloading modules requires a different syntax in Python 2 and Python 3. |
432 | // This provides a consistent syntax no matter what version of Python. |
433 | run_string.Clear(); |
434 | run_string.Printf( |
435 | format: "run_one_line (%s, 'from importlib import reload as reload_module')" , |
436 | m_dictionary_name.c_str()); |
437 | PyRun_SimpleString(run_string.GetData()); |
438 | |
439 | // WARNING: temporary code that loads Cocoa formatters - this should be done |
440 | // on a per-platform basis rather than loading the whole set and letting the |
441 | // individual formatter classes exploit APIs to check whether they can/cannot |
442 | // do their task |
443 | run_string.Clear(); |
444 | run_string.Printf( |
445 | format: "run_one_line (%s, 'import lldb.formatters, lldb.formatters.cpp')" , |
446 | m_dictionary_name.c_str()); |
447 | PyRun_SimpleString(run_string.GetData()); |
448 | run_string.Clear(); |
449 | |
450 | run_string.Printf(format: "run_one_line (%s, 'import lldb.embedded_interpreter; from " |
451 | "lldb.embedded_interpreter import run_python_interpreter; " |
452 | "from lldb.embedded_interpreter import run_one_line')" , |
453 | m_dictionary_name.c_str()); |
454 | PyRun_SimpleString(run_string.GetData()); |
455 | run_string.Clear(); |
456 | |
457 | run_string.Printf(format: "run_one_line (%s, 'lldb.debugger_unique_id = %" PRIu64 |
458 | "')" , |
459 | m_dictionary_name.c_str(), m_debugger.GetID()); |
460 | PyRun_SimpleString(run_string.GetData()); |
461 | } |
462 | |
463 | ScriptInterpreterPythonImpl::~ScriptInterpreterPythonImpl() { |
464 | // the session dictionary may hold objects with complex state which means |
465 | // that they may need to be torn down with some level of smarts and that, in |
466 | // turn, requires a valid thread state force Python to procure itself such a |
467 | // thread state, nuke the session dictionary and then release it for others |
468 | // to use and proceed with the rest of the shutdown |
469 | auto gil_state = PyGILState_Ensure(); |
470 | m_session_dict.Reset(); |
471 | PyGILState_Release(gil_state); |
472 | } |
473 | |
474 | void ScriptInterpreterPythonImpl::IOHandlerActivated(IOHandler &io_handler, |
475 | bool interactive) { |
476 | const char *instructions = nullptr; |
477 | |
478 | switch (m_active_io_handler) { |
479 | case eIOHandlerNone: |
480 | break; |
481 | case eIOHandlerBreakpoint: |
482 | instructions = R"(Enter your Python command(s). Type 'DONE' to end. |
483 | def function (frame, bp_loc, internal_dict): |
484 | """frame: the lldb.SBFrame for the location at which you stopped |
485 | bp_loc: an lldb.SBBreakpointLocation for the breakpoint location information |
486 | internal_dict: an LLDB support object not to be used""" |
487 | )" ; |
488 | break; |
489 | case eIOHandlerWatchpoint: |
490 | instructions = "Enter your Python command(s). Type 'DONE' to end.\n" ; |
491 | break; |
492 | } |
493 | |
494 | if (instructions && interactive) { |
495 | if (LockableStreamFileSP stream_sp = io_handler.GetOutputStreamFileSP()) { |
496 | LockedStreamFile locked_stream = stream_sp->Lock(); |
497 | locked_stream.PutCString(cstr: instructions); |
498 | locked_stream.Flush(); |
499 | } |
500 | } |
501 | } |
502 | |
503 | void ScriptInterpreterPythonImpl::IOHandlerInputComplete(IOHandler &io_handler, |
504 | std::string &data) { |
505 | io_handler.SetIsDone(true); |
506 | bool batch_mode = m_debugger.GetCommandInterpreter().GetBatchCommandMode(); |
507 | |
508 | switch (m_active_io_handler) { |
509 | case eIOHandlerNone: |
510 | break; |
511 | case eIOHandlerBreakpoint: { |
512 | std::vector<std::reference_wrapper<BreakpointOptions>> *bp_options_vec = |
513 | (std::vector<std::reference_wrapper<BreakpointOptions>> *) |
514 | io_handler.GetUserData(); |
515 | for (BreakpointOptions &bp_options : *bp_options_vec) { |
516 | |
517 | auto data_up = std::make_unique<CommandDataPython>(); |
518 | if (!data_up) |
519 | break; |
520 | data_up->user_source.SplitIntoLines(lines: data); |
521 | |
522 | if (GenerateBreakpointCommandCallbackData(input&: data_up->user_source, |
523 | output&: data_up->script_source, |
524 | /*has_extra_args=*/false, |
525 | /*is_callback=*/false) |
526 | .Success()) { |
527 | auto baton_sp = std::make_shared<BreakpointOptions::CommandBaton>( |
528 | args: std::move(data_up)); |
529 | bp_options.SetCallback( |
530 | callback: ScriptInterpreterPythonImpl::BreakpointCallbackFunction, command_baton_sp: baton_sp); |
531 | } else if (!batch_mode) { |
532 | if (LockableStreamFileSP error_sp = io_handler.GetErrorStreamFileSP()) { |
533 | LockedStreamFile locked_stream = error_sp->Lock(); |
534 | locked_stream.Printf(format: "Warning: No command attached to breakpoint.\n" ); |
535 | } |
536 | } |
537 | } |
538 | m_active_io_handler = eIOHandlerNone; |
539 | } break; |
540 | case eIOHandlerWatchpoint: { |
541 | WatchpointOptions *wp_options = |
542 | (WatchpointOptions *)io_handler.GetUserData(); |
543 | auto data_up = std::make_unique<WatchpointOptions::CommandData>(); |
544 | data_up->user_source.SplitIntoLines(lines: data); |
545 | |
546 | if (GenerateWatchpointCommandCallbackData(input&: data_up->user_source, |
547 | output&: data_up->script_source, |
548 | /*is_callback=*/false)) { |
549 | auto baton_sp = |
550 | std::make_shared<WatchpointOptions::CommandBaton>(args: std::move(data_up)); |
551 | wp_options->SetCallback( |
552 | callback: ScriptInterpreterPythonImpl::WatchpointCallbackFunction, baton_sp); |
553 | } else if (!batch_mode) { |
554 | if (LockableStreamFileSP error_sp = io_handler.GetErrorStreamFileSP()) { |
555 | LockedStreamFile locked_stream = error_sp->Lock(); |
556 | locked_stream.Printf(format: "Warning: No command attached to breakpoint.\n" ); |
557 | } |
558 | } |
559 | m_active_io_handler = eIOHandlerNone; |
560 | } break; |
561 | } |
562 | } |
563 | |
564 | lldb::ScriptInterpreterSP |
565 | ScriptInterpreterPythonImpl::CreateInstance(Debugger &debugger) { |
566 | return std::make_shared<ScriptInterpreterPythonImpl>(args&: debugger); |
567 | } |
568 | |
569 | void ScriptInterpreterPythonImpl::LeaveSession() { |
570 | Log *log = GetLog(mask: LLDBLog::Script); |
571 | if (log) |
572 | log->PutCString(cstr: "ScriptInterpreterPythonImpl::LeaveSession()" ); |
573 | |
574 | // Unset the LLDB global variables. |
575 | PyRun_SimpleString("lldb.debugger = None; lldb.target = None; lldb.process " |
576 | "= None; lldb.thread = None; lldb.frame = None" ); |
577 | |
578 | // checking that we have a valid thread state - since we use our own |
579 | // threading and locking in some (rare) cases during cleanup Python may end |
580 | // up believing we have no thread state and PyImport_AddModule will crash if |
581 | // that is the case - since that seems to only happen when destroying the |
582 | // SBDebugger, we can make do without clearing up stdout and stderr |
583 | if (PyThreadState_GetDict()) { |
584 | PythonDictionary &sys_module_dict = GetSysModuleDictionary(); |
585 | if (sys_module_dict.IsValid()) { |
586 | if (m_saved_stdin.IsValid()) { |
587 | sys_module_dict.SetItemForKey(key: PythonString("stdin" ), value: m_saved_stdin); |
588 | m_saved_stdin.Reset(); |
589 | } |
590 | if (m_saved_stdout.IsValid()) { |
591 | sys_module_dict.SetItemForKey(key: PythonString("stdout" ), value: m_saved_stdout); |
592 | m_saved_stdout.Reset(); |
593 | } |
594 | if (m_saved_stderr.IsValid()) { |
595 | sys_module_dict.SetItemForKey(key: PythonString("stderr" ), value: m_saved_stderr); |
596 | m_saved_stderr.Reset(); |
597 | } |
598 | } |
599 | } |
600 | |
601 | m_session_is_active = false; |
602 | } |
603 | |
604 | bool ScriptInterpreterPythonImpl::SetStdHandle(FileSP file_sp, |
605 | const char *py_name, |
606 | PythonObject &save_file, |
607 | const char *mode) { |
608 | if (!file_sp || !*file_sp) { |
609 | save_file.Reset(); |
610 | return false; |
611 | } |
612 | File &file = *file_sp; |
613 | |
614 | // Flush the file before giving it to python to avoid interleaved output. |
615 | file.Flush(); |
616 | |
617 | PythonDictionary &sys_module_dict = GetSysModuleDictionary(); |
618 | |
619 | auto new_file = PythonFile::FromFile(file, mode); |
620 | if (!new_file) { |
621 | llvm::consumeError(Err: new_file.takeError()); |
622 | return false; |
623 | } |
624 | |
625 | save_file = sys_module_dict.GetItemForKey(key: PythonString(py_name)); |
626 | |
627 | sys_module_dict.SetItemForKey(key: PythonString(py_name), value: new_file.get()); |
628 | return true; |
629 | } |
630 | |
631 | bool ScriptInterpreterPythonImpl::EnterSession(uint16_t on_entry_flags, |
632 | FileSP in_sp, FileSP out_sp, |
633 | FileSP err_sp) { |
634 | // If we have already entered the session, without having officially 'left' |
635 | // it, then there is no need to 'enter' it again. |
636 | Log *log = GetLog(mask: LLDBLog::Script); |
637 | if (m_session_is_active) { |
638 | LLDB_LOGF( |
639 | log, |
640 | "ScriptInterpreterPythonImpl::EnterSession(on_entry_flags=0x%" PRIx16 |
641 | ") session is already active, returning without doing anything" , |
642 | on_entry_flags); |
643 | return false; |
644 | } |
645 | |
646 | LLDB_LOGF( |
647 | log, |
648 | "ScriptInterpreterPythonImpl::EnterSession(on_entry_flags=0x%" PRIx16 ")" , |
649 | on_entry_flags); |
650 | |
651 | m_session_is_active = true; |
652 | |
653 | StreamString run_string; |
654 | |
655 | if (on_entry_flags & Locker::InitGlobals) { |
656 | run_string.Printf(format: "run_one_line (%s, 'lldb.debugger_unique_id = %" PRIu64, |
657 | m_dictionary_name.c_str(), m_debugger.GetID()); |
658 | run_string.Printf( |
659 | format: "; lldb.debugger = lldb.SBDebugger.FindDebuggerWithID (%" PRIu64 ")" , |
660 | m_debugger.GetID()); |
661 | run_string.PutCString(cstr: "; lldb.target = lldb.debugger.GetSelectedTarget()" ); |
662 | run_string.PutCString(cstr: "; lldb.process = lldb.target.GetProcess()" ); |
663 | run_string.PutCString(cstr: "; lldb.thread = lldb.process.GetSelectedThread ()" ); |
664 | run_string.PutCString(cstr: "; lldb.frame = lldb.thread.GetSelectedFrame ()" ); |
665 | run_string.PutCString(cstr: "')" ); |
666 | } else { |
667 | // If we aren't initing the globals, we should still always set the |
668 | // debugger (since that is always unique.) |
669 | run_string.Printf(format: "run_one_line (%s, 'lldb.debugger_unique_id = %" PRIu64, |
670 | m_dictionary_name.c_str(), m_debugger.GetID()); |
671 | run_string.Printf( |
672 | format: "; lldb.debugger = lldb.SBDebugger.FindDebuggerWithID (%" PRIu64 ")" , |
673 | m_debugger.GetID()); |
674 | run_string.PutCString(cstr: "')" ); |
675 | } |
676 | |
677 | PyRun_SimpleString(run_string.GetData()); |
678 | run_string.Clear(); |
679 | |
680 | PythonDictionary &sys_module_dict = GetSysModuleDictionary(); |
681 | if (sys_module_dict.IsValid()) { |
682 | lldb::FileSP top_in_sp; |
683 | lldb::LockableStreamFileSP top_out_sp, top_err_sp; |
684 | if (!in_sp || !out_sp || !err_sp || !*in_sp || !*out_sp || !*err_sp) |
685 | m_debugger.AdoptTopIOHandlerFilesIfInvalid(in&: top_in_sp, out&: top_out_sp, |
686 | err&: top_err_sp); |
687 | |
688 | if (on_entry_flags & Locker::NoSTDIN) { |
689 | m_saved_stdin.Reset(); |
690 | } else { |
691 | if (!SetStdHandle(file_sp: in_sp, py_name: "stdin" , save_file&: m_saved_stdin, mode: "r" )) { |
692 | if (top_in_sp) |
693 | SetStdHandle(file_sp: top_in_sp, py_name: "stdin" , save_file&: m_saved_stdin, mode: "r" ); |
694 | } |
695 | } |
696 | |
697 | if (!SetStdHandle(file_sp: out_sp, py_name: "stdout" , save_file&: m_saved_stdout, mode: "w" )) { |
698 | if (top_out_sp) |
699 | SetStdHandle(file_sp: top_out_sp->GetUnlockedFileSP(), py_name: "stdout" , save_file&: m_saved_stdout, |
700 | mode: "w" ); |
701 | } |
702 | |
703 | if (!SetStdHandle(file_sp: err_sp, py_name: "stderr" , save_file&: m_saved_stderr, mode: "w" )) { |
704 | if (top_err_sp) |
705 | SetStdHandle(file_sp: top_err_sp->GetUnlockedFileSP(), py_name: "stderr" , save_file&: m_saved_stderr, |
706 | mode: "w" ); |
707 | } |
708 | } |
709 | |
710 | if (PyErr_Occurred()) |
711 | PyErr_Clear(); |
712 | |
713 | return true; |
714 | } |
715 | |
716 | PythonModule &ScriptInterpreterPythonImpl::GetMainModule() { |
717 | if (!m_main_module.IsValid()) |
718 | m_main_module = unwrapIgnoringErrors(expected: PythonModule::Import(name: "__main__" )); |
719 | return m_main_module; |
720 | } |
721 | |
722 | PythonDictionary &ScriptInterpreterPythonImpl::GetSessionDictionary() { |
723 | if (m_session_dict.IsValid()) |
724 | return m_session_dict; |
725 | |
726 | PythonObject &main_module = GetMainModule(); |
727 | if (!main_module.IsValid()) |
728 | return m_session_dict; |
729 | |
730 | PythonDictionary main_dict(PyRefType::Borrowed, |
731 | PyModule_GetDict(main_module.get())); |
732 | if (!main_dict.IsValid()) |
733 | return m_session_dict; |
734 | |
735 | m_session_dict = unwrapIgnoringErrors( |
736 | expected: As<PythonDictionary>(obj: main_dict.GetItem(key: m_dictionary_name))); |
737 | return m_session_dict; |
738 | } |
739 | |
740 | PythonDictionary &ScriptInterpreterPythonImpl::GetSysModuleDictionary() { |
741 | if (m_sys_module_dict.IsValid()) |
742 | return m_sys_module_dict; |
743 | PythonModule sys_module = unwrapIgnoringErrors(expected: PythonModule::Import(name: "sys" )); |
744 | m_sys_module_dict = sys_module.GetDictionary(); |
745 | return m_sys_module_dict; |
746 | } |
747 | |
748 | llvm::Expected<unsigned> |
749 | ScriptInterpreterPythonImpl::GetMaxPositionalArgumentsForCallable( |
750 | const llvm::StringRef &callable_name) { |
751 | if (callable_name.empty()) { |
752 | return llvm::createStringError(EC: llvm::inconvertibleErrorCode(), |
753 | S: "called with empty callable name." ); |
754 | } |
755 | Locker py_lock(this, |
756 | Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); |
757 | auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>( |
758 | name: m_dictionary_name); |
759 | auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>( |
760 | name: callable_name, dict); |
761 | if (!pfunc.IsAllocated()) { |
762 | return llvm::createStringError(EC: llvm::inconvertibleErrorCode(), |
763 | Fmt: "can't find callable: %s" , |
764 | Vals: callable_name.str().c_str()); |
765 | } |
766 | llvm::Expected<PythonCallable::ArgInfo> arg_info = pfunc.GetArgInfo(); |
767 | if (!arg_info) |
768 | return arg_info.takeError(); |
769 | return arg_info.get().max_positional_args; |
770 | } |
771 | |
772 | static std::string GenerateUniqueName(const char *base_name_wanted, |
773 | uint32_t &functions_counter, |
774 | const void *name_token = nullptr) { |
775 | StreamString sstr; |
776 | |
777 | if (!base_name_wanted) |
778 | return std::string(); |
779 | |
780 | if (!name_token) |
781 | sstr.Printf(format: "%s_%d" , base_name_wanted, functions_counter++); |
782 | else |
783 | sstr.Printf(format: "%s_%p" , base_name_wanted, name_token); |
784 | |
785 | return std::string(sstr.GetString()); |
786 | } |
787 | |
788 | bool ScriptInterpreterPythonImpl::GetEmbeddedInterpreterModuleObjects() { |
789 | if (m_run_one_line_function.IsValid()) |
790 | return true; |
791 | |
792 | PythonObject module(PyRefType::Borrowed, |
793 | PyImport_AddModule(name: "lldb.embedded_interpreter" )); |
794 | if (!module.IsValid()) |
795 | return false; |
796 | |
797 | PythonDictionary module_dict(PyRefType::Borrowed, |
798 | PyModule_GetDict(module.get())); |
799 | if (!module_dict.IsValid()) |
800 | return false; |
801 | |
802 | m_run_one_line_function = |
803 | module_dict.GetItemForKey(key: PythonString("run_one_line" )); |
804 | m_run_one_line_str_global = |
805 | module_dict.GetItemForKey(key: PythonString("g_run_one_line_str" )); |
806 | return m_run_one_line_function.IsValid(); |
807 | } |
808 | |
809 | bool ScriptInterpreterPythonImpl::ExecuteOneLine( |
810 | llvm::StringRef command, CommandReturnObject *result, |
811 | const ExecuteScriptOptions &options) { |
812 | std::string command_str = command.str(); |
813 | |
814 | if (!m_valid_session) |
815 | return false; |
816 | |
817 | if (!command.empty()) { |
818 | // We want to call run_one_line, passing in the dictionary and the command |
819 | // string. We cannot do this through PyRun_SimpleString here because the |
820 | // command string may contain escaped characters, and putting it inside |
821 | // another string to pass to PyRun_SimpleString messes up the escaping. So |
822 | // we use the following more complicated method to pass the command string |
823 | // directly down to Python. |
824 | llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>> |
825 | io_redirect_or_error = ScriptInterpreterIORedirect::Create( |
826 | enable_io: options.GetEnableIO(), debugger&: m_debugger, result); |
827 | if (!io_redirect_or_error) { |
828 | if (result) |
829 | result->AppendErrorWithFormatv( |
830 | format: "failed to redirect I/O: {0}\n" , |
831 | args: llvm::fmt_consume(Item: io_redirect_or_error.takeError())); |
832 | else |
833 | llvm::consumeError(Err: io_redirect_or_error.takeError()); |
834 | return false; |
835 | } |
836 | |
837 | ScriptInterpreterIORedirect &io_redirect = **io_redirect_or_error; |
838 | |
839 | bool success = false; |
840 | { |
841 | // WARNING! It's imperative that this RAII scope be as tight as |
842 | // possible. In particular, the scope must end *before* we try to join |
843 | // the read thread. The reason for this is that a pre-requisite for |
844 | // joining the read thread is that we close the write handle (to break |
845 | // the pipe and cause it to wake up and exit). But acquiring the GIL as |
846 | // below will redirect Python's stdio to use this same handle. If we |
847 | // close the handle while Python is still using it, bad things will |
848 | // happen. |
849 | Locker locker( |
850 | this, |
851 | Locker::AcquireLock | Locker::InitSession | |
852 | (options.GetSetLLDBGlobals() ? Locker::InitGlobals : 0) | |
853 | ((result && result->GetInteractive()) ? 0 : Locker::NoSTDIN), |
854 | Locker::FreeAcquiredLock | Locker::TearDownSession, |
855 | io_redirect.GetInputFile(), io_redirect.GetOutputFile(), |
856 | io_redirect.GetErrorFile()); |
857 | |
858 | // Find the correct script interpreter dictionary in the main module. |
859 | PythonDictionary &session_dict = GetSessionDictionary(); |
860 | if (session_dict.IsValid()) { |
861 | if (GetEmbeddedInterpreterModuleObjects()) { |
862 | if (PyCallable_Check(m_run_one_line_function.get())) { |
863 | PythonObject pargs( |
864 | PyRefType::Owned, |
865 | Py_BuildValue("(Os)" , session_dict.get(), command_str.c_str())); |
866 | if (pargs.IsValid()) { |
867 | PythonObject return_value( |
868 | PyRefType::Owned, |
869 | PyObject_CallObject(callable: m_run_one_line_function.get(), |
870 | args: pargs.get())); |
871 | if (return_value.IsValid()) |
872 | success = true; |
873 | else if (options.GetMaskoutErrors() && PyErr_Occurred()) { |
874 | PyErr_Print(); |
875 | PyErr_Clear(); |
876 | } |
877 | } |
878 | } |
879 | } |
880 | } |
881 | |
882 | io_redirect.Flush(); |
883 | } |
884 | |
885 | if (success) |
886 | return true; |
887 | |
888 | // The one-liner failed. Append the error message. |
889 | if (result) { |
890 | result->AppendErrorWithFormat( |
891 | format: "python failed attempting to evaluate '%s'\n" , command_str.c_str()); |
892 | } |
893 | return false; |
894 | } |
895 | |
896 | if (result) |
897 | result->AppendError(in_string: "empty command passed to python\n" ); |
898 | return false; |
899 | } |
900 | |
901 | void ScriptInterpreterPythonImpl::ExecuteInterpreterLoop() { |
902 | LLDB_SCOPED_TIMER(); |
903 | |
904 | Debugger &debugger = m_debugger; |
905 | |
906 | // At the moment, the only time the debugger does not have an input file |
907 | // handle is when this is called directly from Python, in which case it is |
908 | // both dangerous and unnecessary (not to mention confusing) to try to embed |
909 | // a running interpreter loop inside the already running Python interpreter |
910 | // loop, so we won't do it. |
911 | |
912 | if (!debugger.GetInputFile().IsValid()) |
913 | return; |
914 | |
915 | IOHandlerSP io_handler_sp(new IOHandlerPythonInterpreter(debugger, this)); |
916 | if (io_handler_sp) { |
917 | debugger.RunIOHandlerAsync(reader_sp: io_handler_sp); |
918 | } |
919 | } |
920 | |
921 | bool ScriptInterpreterPythonImpl::Interrupt() { |
922 | #if LLDB_USE_PYTHON_SET_INTERRUPT |
923 | // If the interpreter isn't evaluating any Python at the moment then return |
924 | // false to signal that this function didn't handle the interrupt and the |
925 | // next component should try handling it. |
926 | if (!IsExecutingPython()) |
927 | return false; |
928 | |
929 | // Tell Python that it should pretend to have received a SIGINT. |
930 | PyErr_SetInterrupt(); |
931 | // PyErr_SetInterrupt has no way to return an error so we can only pretend the |
932 | // signal got successfully handled and return true. |
933 | // Python 3.10 introduces PyErr_SetInterruptEx that could return an error, but |
934 | // the error handling is limited to checking the arguments which would be |
935 | // just our (hardcoded) input signal code SIGINT, so that's not useful at all. |
936 | return true; |
937 | #else |
938 | Log *log = GetLog(LLDBLog::Script); |
939 | |
940 | if (IsExecutingPython()) { |
941 | PyThreadState *state = PyThreadState_GET(); |
942 | if (!state) |
943 | state = GetThreadState(); |
944 | if (state) { |
945 | long tid = state->thread_id; |
946 | PyThreadState_Swap(state); |
947 | int num_threads = PyThreadState_SetAsyncExc(tid, PyExc_KeyboardInterrupt); |
948 | LLDB_LOGF(log, |
949 | "ScriptInterpreterPythonImpl::Interrupt() sending " |
950 | "PyExc_KeyboardInterrupt (tid = %li, num_threads = %i)..." , |
951 | tid, num_threads); |
952 | return true; |
953 | } |
954 | } |
955 | LLDB_LOGF(log, |
956 | "ScriptInterpreterPythonImpl::Interrupt() python code not running, " |
957 | "can't interrupt" ); |
958 | return false; |
959 | #endif |
960 | } |
961 | |
962 | bool ScriptInterpreterPythonImpl::ExecuteOneLineWithReturn( |
963 | llvm::StringRef in_string, ScriptInterpreter::ScriptReturnType return_type, |
964 | void *ret_value, const ExecuteScriptOptions &options) { |
965 | |
966 | llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>> |
967 | io_redirect_or_error = ScriptInterpreterIORedirect::Create( |
968 | enable_io: options.GetEnableIO(), debugger&: m_debugger, /*result=*/nullptr); |
969 | |
970 | if (!io_redirect_or_error) { |
971 | llvm::consumeError(Err: io_redirect_or_error.takeError()); |
972 | return false; |
973 | } |
974 | |
975 | ScriptInterpreterIORedirect &io_redirect = **io_redirect_or_error; |
976 | |
977 | Locker locker(this, |
978 | Locker::AcquireLock | Locker::InitSession | |
979 | (options.GetSetLLDBGlobals() ? Locker::InitGlobals : 0) | |
980 | Locker::NoSTDIN, |
981 | Locker::FreeAcquiredLock | Locker::TearDownSession, |
982 | io_redirect.GetInputFile(), io_redirect.GetOutputFile(), |
983 | io_redirect.GetErrorFile()); |
984 | |
985 | PythonModule &main_module = GetMainModule(); |
986 | PythonDictionary globals = main_module.GetDictionary(); |
987 | |
988 | PythonDictionary locals = GetSessionDictionary(); |
989 | if (!locals.IsValid()) |
990 | locals = unwrapIgnoringErrors( |
991 | expected: As<PythonDictionary>(obj: globals.GetAttribute(name: m_dictionary_name))); |
992 | if (!locals.IsValid()) |
993 | locals = globals; |
994 | |
995 | Expected<PythonObject> maybe_py_return = |
996 | runStringOneLine(string: in_string, globals, locals); |
997 | |
998 | if (!maybe_py_return) { |
999 | llvm::handleAllErrors( |
1000 | E: maybe_py_return.takeError(), |
1001 | Handlers: [&](PythonException &E) { |
1002 | E.Restore(); |
1003 | if (options.GetMaskoutErrors()) { |
1004 | if (E.Matches(exc: PyExc_SyntaxError)) { |
1005 | PyErr_Print(); |
1006 | } |
1007 | PyErr_Clear(); |
1008 | } |
1009 | }, |
1010 | Handlers: [](const llvm::ErrorInfoBase &E) {}); |
1011 | return false; |
1012 | } |
1013 | |
1014 | PythonObject py_return = std::move(maybe_py_return.get()); |
1015 | assert(py_return.IsValid()); |
1016 | |
1017 | switch (return_type) { |
1018 | case eScriptReturnTypeCharPtr: // "char *" |
1019 | { |
1020 | const char format[3] = "s#" ; |
1021 | return PyArg_Parse(py_return.get(), format, (char **)ret_value); |
1022 | } |
1023 | case eScriptReturnTypeCharStrOrNone: // char* or NULL if py_return == |
1024 | // Py_None |
1025 | { |
1026 | const char format[3] = "z" ; |
1027 | return PyArg_Parse(py_return.get(), format, (char **)ret_value); |
1028 | } |
1029 | case eScriptReturnTypeBool: { |
1030 | const char format[2] = "b" ; |
1031 | return PyArg_Parse(py_return.get(), format, (bool *)ret_value); |
1032 | } |
1033 | case eScriptReturnTypeShortInt: { |
1034 | const char format[2] = "h" ; |
1035 | return PyArg_Parse(py_return.get(), format, (short *)ret_value); |
1036 | } |
1037 | case eScriptReturnTypeShortIntUnsigned: { |
1038 | const char format[2] = "H" ; |
1039 | return PyArg_Parse(py_return.get(), format, (unsigned short *)ret_value); |
1040 | } |
1041 | case eScriptReturnTypeInt: { |
1042 | const char format[2] = "i" ; |
1043 | return PyArg_Parse(py_return.get(), format, (int *)ret_value); |
1044 | } |
1045 | case eScriptReturnTypeIntUnsigned: { |
1046 | const char format[2] = "I" ; |
1047 | return PyArg_Parse(py_return.get(), format, (unsigned int *)ret_value); |
1048 | } |
1049 | case eScriptReturnTypeLongInt: { |
1050 | const char format[2] = "l" ; |
1051 | return PyArg_Parse(py_return.get(), format, (long *)ret_value); |
1052 | } |
1053 | case eScriptReturnTypeLongIntUnsigned: { |
1054 | const char format[2] = "k" ; |
1055 | return PyArg_Parse(py_return.get(), format, (unsigned long *)ret_value); |
1056 | } |
1057 | case eScriptReturnTypeLongLong: { |
1058 | const char format[2] = "L" ; |
1059 | return PyArg_Parse(py_return.get(), format, (long long *)ret_value); |
1060 | } |
1061 | case eScriptReturnTypeLongLongUnsigned: { |
1062 | const char format[2] = "K" ; |
1063 | return PyArg_Parse(py_return.get(), format, |
1064 | (unsigned long long *)ret_value); |
1065 | } |
1066 | case eScriptReturnTypeFloat: { |
1067 | const char format[2] = "f" ; |
1068 | return PyArg_Parse(py_return.get(), format, (float *)ret_value); |
1069 | } |
1070 | case eScriptReturnTypeDouble: { |
1071 | const char format[2] = "d" ; |
1072 | return PyArg_Parse(py_return.get(), format, (double *)ret_value); |
1073 | } |
1074 | case eScriptReturnTypeChar: { |
1075 | const char format[2] = "c" ; |
1076 | return PyArg_Parse(py_return.get(), format, (char *)ret_value); |
1077 | } |
1078 | case eScriptReturnTypeOpaqueObject: { |
1079 | *((PyObject **)ret_value) = py_return.release(); |
1080 | return true; |
1081 | } |
1082 | } |
1083 | llvm_unreachable("Fully covered switch!" ); |
1084 | } |
1085 | |
1086 | Status ScriptInterpreterPythonImpl::ExecuteMultipleLines( |
1087 | const char *in_string, const ExecuteScriptOptions &options) { |
1088 | |
1089 | if (in_string == nullptr) |
1090 | return Status(); |
1091 | |
1092 | llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>> |
1093 | io_redirect_or_error = ScriptInterpreterIORedirect::Create( |
1094 | enable_io: options.GetEnableIO(), debugger&: m_debugger, /*result=*/nullptr); |
1095 | |
1096 | if (!io_redirect_or_error) |
1097 | return Status::FromError(error: io_redirect_or_error.takeError()); |
1098 | |
1099 | ScriptInterpreterIORedirect &io_redirect = **io_redirect_or_error; |
1100 | |
1101 | Locker locker(this, |
1102 | Locker::AcquireLock | Locker::InitSession | |
1103 | (options.GetSetLLDBGlobals() ? Locker::InitGlobals : 0) | |
1104 | Locker::NoSTDIN, |
1105 | Locker::FreeAcquiredLock | Locker::TearDownSession, |
1106 | io_redirect.GetInputFile(), io_redirect.GetOutputFile(), |
1107 | io_redirect.GetErrorFile()); |
1108 | |
1109 | PythonModule &main_module = GetMainModule(); |
1110 | PythonDictionary globals = main_module.GetDictionary(); |
1111 | |
1112 | PythonDictionary locals = GetSessionDictionary(); |
1113 | if (!locals.IsValid()) |
1114 | locals = unwrapIgnoringErrors( |
1115 | expected: As<PythonDictionary>(obj: globals.GetAttribute(name: m_dictionary_name))); |
1116 | if (!locals.IsValid()) |
1117 | locals = globals; |
1118 | |
1119 | Expected<PythonObject> return_value = |
1120 | runStringMultiLine(string: in_string, globals, locals); |
1121 | |
1122 | if (!return_value) { |
1123 | llvm::Error error = |
1124 | llvm::handleErrors(E: return_value.takeError(), Hs: [&](PythonException &E) { |
1125 | llvm::Error error = llvm::createStringError( |
1126 | EC: llvm::inconvertibleErrorCode(), S: E.ReadBacktrace()); |
1127 | if (!options.GetMaskoutErrors()) |
1128 | E.Restore(); |
1129 | return error; |
1130 | }); |
1131 | return Status::FromError(error: std::move(error)); |
1132 | } |
1133 | |
1134 | return Status(); |
1135 | } |
1136 | |
1137 | void ScriptInterpreterPythonImpl::CollectDataForBreakpointCommandCallback( |
1138 | std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec, |
1139 | CommandReturnObject &result) { |
1140 | m_active_io_handler = eIOHandlerBreakpoint; |
1141 | m_debugger.GetCommandInterpreter().GetPythonCommandsFromIOHandler( |
1142 | prompt: " " , delegate&: *this, baton: &bp_options_vec); |
1143 | } |
1144 | |
1145 | void ScriptInterpreterPythonImpl::CollectDataForWatchpointCommandCallback( |
1146 | WatchpointOptions *wp_options, CommandReturnObject &result) { |
1147 | m_active_io_handler = eIOHandlerWatchpoint; |
1148 | m_debugger.GetCommandInterpreter().GetPythonCommandsFromIOHandler( |
1149 | prompt: " " , delegate&: *this, baton: wp_options); |
1150 | } |
1151 | |
1152 | Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallbackFunction( |
1153 | BreakpointOptions &bp_options, const char *function_name, |
1154 | StructuredData::ObjectSP ) { |
1155 | Status error; |
1156 | // For now just cons up a oneliner that calls the provided function. |
1157 | std::string function_signature = function_name; |
1158 | |
1159 | llvm::Expected<unsigned> maybe_args = |
1160 | GetMaxPositionalArgumentsForCallable(callable_name: function_name); |
1161 | if (!maybe_args) { |
1162 | error = Status::FromErrorStringWithFormat( |
1163 | format: "could not get num args: %s" , |
1164 | llvm::toString(E: maybe_args.takeError()).c_str()); |
1165 | return error; |
1166 | } |
1167 | size_t max_args = *maybe_args; |
1168 | |
1169 | bool = false; |
1170 | if (max_args >= 4) { |
1171 | uses_extra_args = true; |
1172 | function_signature += "(frame, bp_loc, extra_args, internal_dict)" ; |
1173 | } else if (max_args >= 3) { |
1174 | if (extra_args_sp) { |
1175 | error = Status::FromErrorStringWithFormat( |
1176 | format: "cannot pass extra_args to a three argument callback" ); |
1177 | return error; |
1178 | } |
1179 | uses_extra_args = false; |
1180 | function_signature += "(frame, bp_loc, internal_dict)" ; |
1181 | } else { |
1182 | error = Status::FromErrorStringWithFormat(format: "expected 3 or 4 argument " |
1183 | "function, %s can only take %zu" , |
1184 | function_name, max_args); |
1185 | return error; |
1186 | } |
1187 | |
1188 | SetBreakpointCommandCallback(bp_options, command_body_text: function_signature.c_str(), |
1189 | extra_args_sp, uses_extra_args, |
1190 | /*is_callback=*/true); |
1191 | return error; |
1192 | } |
1193 | |
1194 | Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback( |
1195 | BreakpointOptions &bp_options, |
1196 | std::unique_ptr<BreakpointOptions::CommandData> &cmd_data_up) { |
1197 | Status error; |
1198 | error = GenerateBreakpointCommandCallbackData(input&: cmd_data_up->user_source, |
1199 | output&: cmd_data_up->script_source, |
1200 | /*has_extra_args=*/false, |
1201 | /*is_callback=*/false); |
1202 | if (error.Fail()) { |
1203 | return error; |
1204 | } |
1205 | auto baton_sp = |
1206 | std::make_shared<BreakpointOptions::CommandBaton>(args: std::move(cmd_data_up)); |
1207 | bp_options.SetCallback( |
1208 | callback: ScriptInterpreterPythonImpl::BreakpointCallbackFunction, command_baton_sp: baton_sp); |
1209 | return error; |
1210 | } |
1211 | |
1212 | Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback( |
1213 | BreakpointOptions &bp_options, const char *command_body_text, |
1214 | bool is_callback) { |
1215 | return SetBreakpointCommandCallback(bp_options, command_body_text, extra_args_sp: {}, |
1216 | /*uses_extra_args=*/false, is_callback); |
1217 | } |
1218 | |
1219 | // Set a Python one-liner as the callback for the breakpoint. |
1220 | Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback( |
1221 | BreakpointOptions &bp_options, const char *command_body_text, |
1222 | StructuredData::ObjectSP , bool , |
1223 | bool is_callback) { |
1224 | auto data_up = std::make_unique<CommandDataPython>(args&: extra_args_sp); |
1225 | // Split the command_body_text into lines, and pass that to |
1226 | // GenerateBreakpointCommandCallbackData. That will wrap the body in an |
1227 | // auto-generated function, and return the function name in script_source. |
1228 | // That is what the callback will actually invoke. |
1229 | |
1230 | data_up->user_source.SplitIntoLines(lines: command_body_text); |
1231 | Status error = GenerateBreakpointCommandCallbackData( |
1232 | input&: data_up->user_source, output&: data_up->script_source, has_extra_args: uses_extra_args, |
1233 | is_callback); |
1234 | if (error.Success()) { |
1235 | auto baton_sp = |
1236 | std::make_shared<BreakpointOptions::CommandBaton>(args: std::move(data_up)); |
1237 | bp_options.SetCallback( |
1238 | callback: ScriptInterpreterPythonImpl::BreakpointCallbackFunction, command_baton_sp: baton_sp); |
1239 | return error; |
1240 | } |
1241 | return error; |
1242 | } |
1243 | |
1244 | // Set a Python one-liner as the callback for the watchpoint. |
1245 | void ScriptInterpreterPythonImpl::SetWatchpointCommandCallback( |
1246 | WatchpointOptions *wp_options, const char *user_input, bool is_callback) { |
1247 | auto data_up = std::make_unique<WatchpointOptions::CommandData>(); |
1248 | |
1249 | // It's necessary to set both user_source and script_source to the oneliner. |
1250 | // The former is used to generate callback description (as in watchpoint |
1251 | // command list) while the latter is used for Python to interpret during the |
1252 | // actual callback. |
1253 | |
1254 | data_up->user_source.AppendString(str: user_input); |
1255 | data_up->script_source.assign(s: user_input); |
1256 | |
1257 | if (GenerateWatchpointCommandCallbackData( |
1258 | input&: data_up->user_source, output&: data_up->script_source, is_callback)) { |
1259 | auto baton_sp = |
1260 | std::make_shared<WatchpointOptions::CommandBaton>(args: std::move(data_up)); |
1261 | wp_options->SetCallback( |
1262 | callback: ScriptInterpreterPythonImpl::WatchpointCallbackFunction, baton_sp); |
1263 | } |
1264 | } |
1265 | |
1266 | Status ScriptInterpreterPythonImpl::ExportFunctionDefinitionToInterpreter( |
1267 | StringList &function_def) { |
1268 | // Convert StringList to one long, newline delimited, const char *. |
1269 | std::string function_def_string(function_def.CopyList()); |
1270 | LLDB_LOG(GetLog(LLDBLog::Script), "Added Function:\n%s\n" , |
1271 | function_def_string.c_str()); |
1272 | |
1273 | Status error = ExecuteMultipleLines( |
1274 | in_string: function_def_string.c_str(), options: ExecuteScriptOptions().SetEnableIO(false)); |
1275 | return error; |
1276 | } |
1277 | |
1278 | Status ScriptInterpreterPythonImpl::GenerateFunction(const char *signature, |
1279 | const StringList &input, |
1280 | bool is_callback) { |
1281 | Status error; |
1282 | int num_lines = input.GetSize(); |
1283 | if (num_lines == 0) { |
1284 | error = Status::FromErrorString(str: "No input data." ); |
1285 | return error; |
1286 | } |
1287 | |
1288 | if (!signature || *signature == 0) { |
1289 | error = Status::FromErrorString(str: "No output function name." ); |
1290 | return error; |
1291 | } |
1292 | |
1293 | StreamString sstr; |
1294 | StringList auto_generated_function; |
1295 | auto_generated_function.AppendString(str: signature); |
1296 | auto_generated_function.AppendString( |
1297 | str: " global_dict = globals()" ); // Grab the global dictionary |
1298 | auto_generated_function.AppendString( |
1299 | str: " new_keys = internal_dict.keys()" ); // Make a list of keys in the |
1300 | // session dict |
1301 | auto_generated_function.AppendString( |
1302 | str: " old_keys = global_dict.keys()" ); // Save list of keys in global dict |
1303 | auto_generated_function.AppendString( |
1304 | str: " global_dict.update(internal_dict)" ); // Add the session dictionary |
1305 | // to the global dictionary. |
1306 | |
1307 | if (is_callback) { |
1308 | // If the user input is a callback to a python function, make sure the input |
1309 | // is only 1 line, otherwise appending the user input would break the |
1310 | // generated wrapped function |
1311 | if (num_lines == 1) { |
1312 | sstr.Clear(); |
1313 | sstr.Printf(format: " __return_val = %s" , input.GetStringAtIndex(idx: 0)); |
1314 | auto_generated_function.AppendString(str: sstr.GetData()); |
1315 | } else { |
1316 | return Status::FromErrorString( |
1317 | str: "ScriptInterpreterPythonImpl::GenerateFunction(is_callback=" |
1318 | "true) = ERROR: python function is multiline." ); |
1319 | } |
1320 | } else { |
1321 | auto_generated_function.AppendString( |
1322 | str: " __return_val = None" ); // Initialize user callback return value. |
1323 | auto_generated_function.AppendString( |
1324 | str: " def __user_code():" ); // Create a nested function that will wrap |
1325 | // the user input. This is necessary to |
1326 | // capture the return value of the user input |
1327 | // and prevent early returns. |
1328 | for (int i = 0; i < num_lines; ++i) { |
1329 | sstr.Clear(); |
1330 | sstr.Printf(format: " %s" , input.GetStringAtIndex(idx: i)); |
1331 | auto_generated_function.AppendString(str: sstr.GetData()); |
1332 | } |
1333 | auto_generated_function.AppendString( |
1334 | str: " __return_val = __user_code()" ); // Call user code and capture |
1335 | // return value |
1336 | } |
1337 | auto_generated_function.AppendString( |
1338 | str: " for key in new_keys:" ); // Iterate over all the keys from session |
1339 | // dict |
1340 | auto_generated_function.AppendString( |
1341 | str: " if key in old_keys:" ); // If key was originally in |
1342 | // global dict |
1343 | auto_generated_function.AppendString( |
1344 | str: " internal_dict[key] = global_dict[key]" ); // Update it |
1345 | auto_generated_function.AppendString( |
1346 | str: " elif key in global_dict:" ); // Then if it is still in the |
1347 | // global dict |
1348 | auto_generated_function.AppendString( |
1349 | str: " del global_dict[key]" ); // remove key/value from the |
1350 | // global dict |
1351 | auto_generated_function.AppendString( |
1352 | str: " return __return_val" ); // Return the user callback return value. |
1353 | |
1354 | // Verify that the results are valid Python. |
1355 | error = ExportFunctionDefinitionToInterpreter(function_def&: auto_generated_function); |
1356 | |
1357 | return error; |
1358 | } |
1359 | |
1360 | bool ScriptInterpreterPythonImpl::GenerateTypeScriptFunction( |
1361 | StringList &user_input, std::string &output, const void *name_token) { |
1362 | static uint32_t num_created_functions = 0; |
1363 | user_input.RemoveBlankLines(); |
1364 | StreamString sstr; |
1365 | |
1366 | // Check to see if we have any data; if not, just return. |
1367 | if (user_input.GetSize() == 0) |
1368 | return false; |
1369 | |
1370 | // Take what the user wrote, wrap it all up inside one big auto-generated |
1371 | // Python function, passing in the ValueObject as parameter to the function. |
1372 | |
1373 | std::string auto_generated_function_name( |
1374 | GenerateUniqueName(base_name_wanted: "lldb_autogen_python_type_print_func" , |
1375 | functions_counter&: num_created_functions, name_token)); |
1376 | sstr.Printf(format: "def %s (valobj, internal_dict):" , |
1377 | auto_generated_function_name.c_str()); |
1378 | |
1379 | if (!GenerateFunction(signature: sstr.GetData(), input: user_input, /*is_callback=*/false) |
1380 | .Success()) |
1381 | return false; |
1382 | |
1383 | // Store the name of the auto-generated function to be called. |
1384 | output.assign(str: auto_generated_function_name); |
1385 | return true; |
1386 | } |
1387 | |
1388 | bool ScriptInterpreterPythonImpl::GenerateScriptAliasFunction( |
1389 | StringList &user_input, std::string &output) { |
1390 | static uint32_t num_created_functions = 0; |
1391 | user_input.RemoveBlankLines(); |
1392 | StreamString sstr; |
1393 | |
1394 | // Check to see if we have any data; if not, just return. |
1395 | if (user_input.GetSize() == 0) |
1396 | return false; |
1397 | |
1398 | std::string auto_generated_function_name(GenerateUniqueName( |
1399 | base_name_wanted: "lldb_autogen_python_cmd_alias_func" , functions_counter&: num_created_functions)); |
1400 | |
1401 | sstr.Printf(format: "def %s (debugger, args, exe_ctx, result, internal_dict):" , |
1402 | auto_generated_function_name.c_str()); |
1403 | |
1404 | if (!GenerateFunction(signature: sstr.GetData(), input: user_input, /*is_callback=*/false) |
1405 | .Success()) |
1406 | return false; |
1407 | |
1408 | // Store the name of the auto-generated function to be called. |
1409 | output.assign(str: auto_generated_function_name); |
1410 | return true; |
1411 | } |
1412 | |
1413 | bool ScriptInterpreterPythonImpl::GenerateTypeSynthClass( |
1414 | StringList &user_input, std::string &output, const void *name_token) { |
1415 | static uint32_t num_created_classes = 0; |
1416 | user_input.RemoveBlankLines(); |
1417 | int num_lines = user_input.GetSize(); |
1418 | StreamString sstr; |
1419 | |
1420 | // Check to see if we have any data; if not, just return. |
1421 | if (user_input.GetSize() == 0) |
1422 | return false; |
1423 | |
1424 | // Wrap all user input into a Python class |
1425 | |
1426 | std::string auto_generated_class_name(GenerateUniqueName( |
1427 | base_name_wanted: "lldb_autogen_python_type_synth_class" , functions_counter&: num_created_classes, name_token)); |
1428 | |
1429 | StringList auto_generated_class; |
1430 | |
1431 | // Create the function name & definition string. |
1432 | |
1433 | sstr.Printf(format: "class %s:" , auto_generated_class_name.c_str()); |
1434 | auto_generated_class.AppendString(str: sstr.GetString()); |
1435 | |
1436 | // Wrap everything up inside the class, increasing the indentation. we don't |
1437 | // need to play any fancy indentation tricks here because there is no |
1438 | // surrounding code whose indentation we need to honor |
1439 | for (int i = 0; i < num_lines; ++i) { |
1440 | sstr.Clear(); |
1441 | sstr.Printf(format: " %s" , user_input.GetStringAtIndex(idx: i)); |
1442 | auto_generated_class.AppendString(str: sstr.GetString()); |
1443 | } |
1444 | |
1445 | // Verify that the results are valid Python. (even though the method is |
1446 | // ExportFunctionDefinitionToInterpreter, a class will actually be exported) |
1447 | // (TODO: rename that method to ExportDefinitionToInterpreter) |
1448 | if (!ExportFunctionDefinitionToInterpreter(function_def&: auto_generated_class).Success()) |
1449 | return false; |
1450 | |
1451 | // Store the name of the auto-generated class |
1452 | |
1453 | output.assign(str: auto_generated_class_name); |
1454 | return true; |
1455 | } |
1456 | |
1457 | StructuredData::GenericSP |
1458 | ScriptInterpreterPythonImpl::CreateFrameRecognizer(const char *class_name) { |
1459 | if (class_name == nullptr || class_name[0] == '\0') |
1460 | return StructuredData::GenericSP(); |
1461 | |
1462 | Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); |
1463 | PythonObject ret_val = SWIGBridge::LLDBSWIGPython_CreateFrameRecognizer( |
1464 | python_class_name: class_name, session_dictionary_name: m_dictionary_name.c_str()); |
1465 | |
1466 | return StructuredData::GenericSP( |
1467 | new StructuredPythonObject(std::move(ret_val))); |
1468 | } |
1469 | |
1470 | lldb::ValueObjectListSP ScriptInterpreterPythonImpl::GetRecognizedArguments( |
1471 | const StructuredData::ObjectSP &os_plugin_object_sp, |
1472 | lldb::StackFrameSP frame_sp) { |
1473 | Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); |
1474 | |
1475 | if (!os_plugin_object_sp) |
1476 | return ValueObjectListSP(); |
1477 | |
1478 | StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric(); |
1479 | if (!generic) |
1480 | return nullptr; |
1481 | |
1482 | PythonObject implementor(PyRefType::Borrowed, |
1483 | (PyObject *)generic->GetValue()); |
1484 | |
1485 | if (!implementor.IsAllocated()) |
1486 | return ValueObjectListSP(); |
1487 | |
1488 | PythonObject py_return(PyRefType::Owned, |
1489 | SWIGBridge::LLDBSwigPython_GetRecognizedArguments( |
1490 | implementor: implementor.get(), frame_sp)); |
1491 | |
1492 | // if it fails, print the error but otherwise go on |
1493 | if (PyErr_Occurred()) { |
1494 | PyErr_Print(); |
1495 | PyErr_Clear(); |
1496 | } |
1497 | if (py_return.get()) { |
1498 | PythonList result_list(PyRefType::Borrowed, py_return.get()); |
1499 | ValueObjectListSP result = ValueObjectListSP(new ValueObjectList()); |
1500 | for (size_t i = 0; i < result_list.GetSize(); i++) { |
1501 | PyObject *item = result_list.GetItemAtIndex(index: i).get(); |
1502 | lldb::SBValue *sb_value_ptr = |
1503 | (lldb::SBValue *)LLDBSWIGPython_CastPyObjectToSBValue(data: item); |
1504 | auto valobj_sp = |
1505 | SWIGBridge::LLDBSWIGPython_GetValueObjectSPFromSBValue(data: sb_value_ptr); |
1506 | if (valobj_sp) |
1507 | result->Append(val_obj_sp: valobj_sp); |
1508 | } |
1509 | return result; |
1510 | } |
1511 | return ValueObjectListSP(); |
1512 | } |
1513 | |
1514 | bool ScriptInterpreterPythonImpl::ShouldHide( |
1515 | const StructuredData::ObjectSP &os_plugin_object_sp, |
1516 | lldb::StackFrameSP frame_sp) { |
1517 | Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); |
1518 | |
1519 | if (!os_plugin_object_sp) |
1520 | return false; |
1521 | |
1522 | StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric(); |
1523 | if (!generic) |
1524 | return false; |
1525 | |
1526 | PythonObject implementor(PyRefType::Borrowed, |
1527 | (PyObject *)generic->GetValue()); |
1528 | |
1529 | if (!implementor.IsAllocated()) |
1530 | return false; |
1531 | |
1532 | bool result = |
1533 | SWIGBridge::LLDBSwigPython_ShouldHide(implementor: implementor.get(), frame_sp); |
1534 | |
1535 | // if it fails, print the error but otherwise go on |
1536 | if (PyErr_Occurred()) { |
1537 | PyErr_Print(); |
1538 | PyErr_Clear(); |
1539 | } |
1540 | return result; |
1541 | } |
1542 | |
1543 | ScriptedProcessInterfaceUP |
1544 | ScriptInterpreterPythonImpl::CreateScriptedProcessInterface() { |
1545 | return std::make_unique<ScriptedProcessPythonInterface>(args&: *this); |
1546 | } |
1547 | |
1548 | ScriptedStopHookInterfaceSP |
1549 | ScriptInterpreterPythonImpl::CreateScriptedStopHookInterface() { |
1550 | return std::make_shared<ScriptedStopHookPythonInterface>(args&: *this); |
1551 | } |
1552 | |
1553 | ScriptedThreadInterfaceSP |
1554 | ScriptInterpreterPythonImpl::CreateScriptedThreadInterface() { |
1555 | return std::make_shared<ScriptedThreadPythonInterface>(args&: *this); |
1556 | } |
1557 | |
1558 | ScriptedThreadPlanInterfaceSP |
1559 | ScriptInterpreterPythonImpl::CreateScriptedThreadPlanInterface() { |
1560 | return std::make_shared<ScriptedThreadPlanPythonInterface>(args&: *this); |
1561 | } |
1562 | |
1563 | OperatingSystemInterfaceSP |
1564 | ScriptInterpreterPythonImpl::CreateOperatingSystemInterface() { |
1565 | return std::make_shared<OperatingSystemPythonInterface>(args&: *this); |
1566 | } |
1567 | |
1568 | StructuredData::ObjectSP |
1569 | ScriptInterpreterPythonImpl::CreateStructuredDataFromScriptObject( |
1570 | ScriptObject obj) { |
1571 | void *ptr = const_cast<void *>(obj.GetPointer()); |
1572 | Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); |
1573 | PythonObject py_obj(PyRefType::Borrowed, static_cast<PyObject *>(ptr)); |
1574 | if (!py_obj.IsValid() || py_obj.IsNone()) |
1575 | return {}; |
1576 | return py_obj.CreateStructuredObject(); |
1577 | } |
1578 | |
1579 | StructuredData::GenericSP |
1580 | ScriptInterpreterPythonImpl::CreateScriptedBreakpointResolver( |
1581 | const char *class_name, const StructuredDataImpl &args_data, |
1582 | lldb::BreakpointSP &bkpt_sp) { |
1583 | |
1584 | if (class_name == nullptr || class_name[0] == '\0') |
1585 | return StructuredData::GenericSP(); |
1586 | |
1587 | if (!bkpt_sp.get()) |
1588 | return StructuredData::GenericSP(); |
1589 | |
1590 | Debugger &debugger = bkpt_sp->GetTarget().GetDebugger(); |
1591 | ScriptInterpreterPythonImpl *python_interpreter = |
1592 | GetPythonInterpreter(debugger); |
1593 | |
1594 | if (!python_interpreter) |
1595 | return StructuredData::GenericSP(); |
1596 | |
1597 | Locker py_lock(this, |
1598 | Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); |
1599 | |
1600 | PythonObject ret_val = |
1601 | SWIGBridge::LLDBSwigPythonCreateScriptedBreakpointResolver( |
1602 | python_class_name: class_name, session_dictionary_name: python_interpreter->m_dictionary_name.c_str(), args: args_data, |
1603 | bkpt_sp); |
1604 | |
1605 | return StructuredData::GenericSP( |
1606 | new StructuredPythonObject(std::move(ret_val))); |
1607 | } |
1608 | |
1609 | bool ScriptInterpreterPythonImpl::ScriptedBreakpointResolverSearchCallback( |
1610 | StructuredData::GenericSP implementor_sp, SymbolContext *sym_ctx) { |
1611 | bool should_continue = false; |
1612 | |
1613 | if (implementor_sp) { |
1614 | Locker py_lock(this, |
1615 | Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); |
1616 | should_continue = SWIGBridge::LLDBSwigPythonCallBreakpointResolver( |
1617 | implementor: implementor_sp->GetValue(), method_name: "__callback__" , sym_ctx); |
1618 | if (PyErr_Occurred()) { |
1619 | PyErr_Print(); |
1620 | PyErr_Clear(); |
1621 | } |
1622 | } |
1623 | return should_continue; |
1624 | } |
1625 | |
1626 | lldb::SearchDepth |
1627 | ScriptInterpreterPythonImpl::ScriptedBreakpointResolverSearchDepth( |
1628 | StructuredData::GenericSP implementor_sp) { |
1629 | int depth_as_int = lldb::eSearchDepthModule; |
1630 | if (implementor_sp) { |
1631 | Locker py_lock(this, |
1632 | Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); |
1633 | depth_as_int = SWIGBridge::LLDBSwigPythonCallBreakpointResolver( |
1634 | implementor: implementor_sp->GetValue(), method_name: "__get_depth__" , sym_ctx: nullptr); |
1635 | if (PyErr_Occurred()) { |
1636 | PyErr_Print(); |
1637 | PyErr_Clear(); |
1638 | } |
1639 | } |
1640 | if (depth_as_int == lldb::eSearchDepthInvalid) |
1641 | return lldb::eSearchDepthModule; |
1642 | |
1643 | if (depth_as_int <= lldb::kLastSearchDepthKind) |
1644 | return (lldb::SearchDepth)depth_as_int; |
1645 | return lldb::eSearchDepthModule; |
1646 | } |
1647 | |
1648 | StructuredData::ObjectSP |
1649 | ScriptInterpreterPythonImpl::LoadPluginModule(const FileSpec &file_spec, |
1650 | lldb_private::Status &error) { |
1651 | if (!FileSystem::Instance().Exists(file_spec)) { |
1652 | error = Status::FromErrorString(str: "no such file" ); |
1653 | return StructuredData::ObjectSP(); |
1654 | } |
1655 | |
1656 | StructuredData::ObjectSP module_sp; |
1657 | |
1658 | LoadScriptOptions load_script_options = |
1659 | LoadScriptOptions().SetInitSession(true).SetSilent(false); |
1660 | if (LoadScriptingModule(filename: file_spec.GetPath().c_str(), options: load_script_options, |
1661 | error, module_sp: &module_sp)) |
1662 | return module_sp; |
1663 | |
1664 | return StructuredData::ObjectSP(); |
1665 | } |
1666 | |
1667 | StructuredData::DictionarySP ScriptInterpreterPythonImpl::GetDynamicSettings( |
1668 | StructuredData::ObjectSP plugin_module_sp, Target *target, |
1669 | const char *setting_name, lldb_private::Status &error) { |
1670 | if (!plugin_module_sp || !target || !setting_name || !setting_name[0]) |
1671 | return StructuredData::DictionarySP(); |
1672 | StructuredData::Generic *generic = plugin_module_sp->GetAsGeneric(); |
1673 | if (!generic) |
1674 | return StructuredData::DictionarySP(); |
1675 | |
1676 | Locker py_lock(this, |
1677 | Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); |
1678 | TargetSP target_sp(target->shared_from_this()); |
1679 | |
1680 | auto setting = (PyObject *)SWIGBridge::LLDBSWIGPython_GetDynamicSetting( |
1681 | module: generic->GetValue(), setting: setting_name, target_sp); |
1682 | |
1683 | if (!setting) |
1684 | return StructuredData::DictionarySP(); |
1685 | |
1686 | PythonDictionary py_dict = |
1687 | unwrapIgnoringErrors(expected: As<PythonDictionary>(obj: Take<PythonObject>(obj: setting))); |
1688 | |
1689 | if (!py_dict) |
1690 | return StructuredData::DictionarySP(); |
1691 | |
1692 | return py_dict.CreateStructuredDictionary(); |
1693 | } |
1694 | |
1695 | StructuredData::ObjectSP |
1696 | ScriptInterpreterPythonImpl::CreateSyntheticScriptedProvider( |
1697 | const char *class_name, lldb::ValueObjectSP valobj) { |
1698 | if (class_name == nullptr || class_name[0] == '\0') |
1699 | return StructuredData::ObjectSP(); |
1700 | |
1701 | if (!valobj.get()) |
1702 | return StructuredData::ObjectSP(); |
1703 | |
1704 | ExecutionContext exe_ctx(valobj->GetExecutionContextRef()); |
1705 | Target *target = exe_ctx.GetTargetPtr(); |
1706 | |
1707 | if (!target) |
1708 | return StructuredData::ObjectSP(); |
1709 | |
1710 | Debugger &debugger = target->GetDebugger(); |
1711 | ScriptInterpreterPythonImpl *python_interpreter = |
1712 | GetPythonInterpreter(debugger); |
1713 | |
1714 | if (!python_interpreter) |
1715 | return StructuredData::ObjectSP(); |
1716 | |
1717 | Locker py_lock(this, |
1718 | Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); |
1719 | PythonObject ret_val = SWIGBridge::LLDBSwigPythonCreateSyntheticProvider( |
1720 | python_class_name: class_name, session_dictionary_name: python_interpreter->m_dictionary_name.c_str(), valobj_sp: valobj); |
1721 | |
1722 | return StructuredData::ObjectSP( |
1723 | new StructuredPythonObject(std::move(ret_val))); |
1724 | } |
1725 | |
1726 | StructuredData::GenericSP |
1727 | ScriptInterpreterPythonImpl::CreateScriptCommandObject(const char *class_name) { |
1728 | DebuggerSP debugger_sp(m_debugger.shared_from_this()); |
1729 | |
1730 | if (class_name == nullptr || class_name[0] == '\0') |
1731 | return StructuredData::GenericSP(); |
1732 | |
1733 | if (!debugger_sp.get()) |
1734 | return StructuredData::GenericSP(); |
1735 | |
1736 | Locker py_lock(this, |
1737 | Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); |
1738 | PythonObject ret_val = SWIGBridge::LLDBSwigPythonCreateCommandObject( |
1739 | python_class_name: class_name, session_dictionary_name: m_dictionary_name.c_str(), debugger_sp); |
1740 | |
1741 | if (ret_val.IsValid()) |
1742 | return StructuredData::GenericSP( |
1743 | new StructuredPythonObject(std::move(ret_val))); |
1744 | else |
1745 | return {}; |
1746 | } |
1747 | |
1748 | bool ScriptInterpreterPythonImpl::GenerateTypeScriptFunction( |
1749 | const char *oneliner, std::string &output, const void *name_token) { |
1750 | StringList input; |
1751 | input.SplitIntoLines(lines: oneliner, len: strlen(s: oneliner)); |
1752 | return GenerateTypeScriptFunction(user_input&: input, output, name_token); |
1753 | } |
1754 | |
1755 | bool ScriptInterpreterPythonImpl::GenerateTypeSynthClass( |
1756 | const char *oneliner, std::string &output, const void *name_token) { |
1757 | StringList input; |
1758 | input.SplitIntoLines(lines: oneliner, len: strlen(s: oneliner)); |
1759 | return GenerateTypeSynthClass(user_input&: input, output, name_token); |
1760 | } |
1761 | |
1762 | Status ScriptInterpreterPythonImpl::GenerateBreakpointCommandCallbackData( |
1763 | StringList &user_input, std::string &output, bool , |
1764 | bool is_callback) { |
1765 | static uint32_t num_created_functions = 0; |
1766 | user_input.RemoveBlankLines(); |
1767 | StreamString sstr; |
1768 | Status error; |
1769 | if (user_input.GetSize() == 0) { |
1770 | error = Status::FromErrorString(str: "No input data." ); |
1771 | return error; |
1772 | } |
1773 | |
1774 | std::string auto_generated_function_name(GenerateUniqueName( |
1775 | base_name_wanted: "lldb_autogen_python_bp_callback_func_" , functions_counter&: num_created_functions)); |
1776 | if (has_extra_args) |
1777 | sstr.Printf(format: "def %s (frame, bp_loc, extra_args, internal_dict):" , |
1778 | auto_generated_function_name.c_str()); |
1779 | else |
1780 | sstr.Printf(format: "def %s (frame, bp_loc, internal_dict):" , |
1781 | auto_generated_function_name.c_str()); |
1782 | |
1783 | error = GenerateFunction(signature: sstr.GetData(), input: user_input, is_callback); |
1784 | if (!error.Success()) |
1785 | return error; |
1786 | |
1787 | // Store the name of the auto-generated function to be called. |
1788 | output.assign(str: auto_generated_function_name); |
1789 | return error; |
1790 | } |
1791 | |
1792 | bool ScriptInterpreterPythonImpl::GenerateWatchpointCommandCallbackData( |
1793 | StringList &user_input, std::string &output, bool is_callback) { |
1794 | static uint32_t num_created_functions = 0; |
1795 | user_input.RemoveBlankLines(); |
1796 | StreamString sstr; |
1797 | |
1798 | if (user_input.GetSize() == 0) |
1799 | return false; |
1800 | |
1801 | std::string auto_generated_function_name(GenerateUniqueName( |
1802 | base_name_wanted: "lldb_autogen_python_wp_callback_func_" , functions_counter&: num_created_functions)); |
1803 | sstr.Printf(format: "def %s (frame, wp, internal_dict):" , |
1804 | auto_generated_function_name.c_str()); |
1805 | |
1806 | if (!GenerateFunction(signature: sstr.GetData(), input: user_input, is_callback).Success()) |
1807 | return false; |
1808 | |
1809 | // Store the name of the auto-generated function to be called. |
1810 | output.assign(str: auto_generated_function_name); |
1811 | return true; |
1812 | } |
1813 | |
1814 | bool ScriptInterpreterPythonImpl::GetScriptedSummary( |
1815 | const char *python_function_name, lldb::ValueObjectSP valobj, |
1816 | StructuredData::ObjectSP &callee_wrapper_sp, |
1817 | const TypeSummaryOptions &options, std::string &retval) { |
1818 | |
1819 | LLDB_SCOPED_TIMER(); |
1820 | |
1821 | if (!valobj.get()) { |
1822 | retval.assign(s: "<no object>" ); |
1823 | return false; |
1824 | } |
1825 | |
1826 | void *old_callee = nullptr; |
1827 | StructuredData::Generic *generic = nullptr; |
1828 | if (callee_wrapper_sp) { |
1829 | generic = callee_wrapper_sp->GetAsGeneric(); |
1830 | if (generic) |
1831 | old_callee = generic->GetValue(); |
1832 | } |
1833 | void *new_callee = old_callee; |
1834 | |
1835 | bool ret_val; |
1836 | if (python_function_name && *python_function_name) { |
1837 | { |
1838 | Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | |
1839 | Locker::NoSTDIN); |
1840 | { |
1841 | TypeSummaryOptionsSP options_sp(new TypeSummaryOptions(options)); |
1842 | |
1843 | static Timer::Category func_cat("LLDBSwigPythonCallTypeScript" ); |
1844 | Timer scoped_timer(func_cat, "LLDBSwigPythonCallTypeScript" ); |
1845 | ret_val = SWIGBridge::LLDBSwigPythonCallTypeScript( |
1846 | python_function_name, session_dictionary: GetSessionDictionary().get(), valobj_sp: valobj, |
1847 | pyfunct_wrapper: &new_callee, options_sp, retval); |
1848 | } |
1849 | } |
1850 | } else { |
1851 | retval.assign(s: "<no function name>" ); |
1852 | return false; |
1853 | } |
1854 | |
1855 | if (new_callee && old_callee != new_callee) { |
1856 | Locker py_lock(this, |
1857 | Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); |
1858 | callee_wrapper_sp = std::make_shared<StructuredPythonObject>( |
1859 | args: PythonObject(PyRefType::Borrowed, static_cast<PyObject *>(new_callee))); |
1860 | } |
1861 | |
1862 | return ret_val; |
1863 | } |
1864 | |
1865 | bool ScriptInterpreterPythonImpl::FormatterCallbackFunction( |
1866 | const char *python_function_name, TypeImplSP type_impl_sp) { |
1867 | Locker py_lock(this, |
1868 | Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); |
1869 | return SWIGBridge::LLDBSwigPythonFormatterCallbackFunction( |
1870 | python_function_name, session_dictionary_name: m_dictionary_name.c_str(), type_impl_sp); |
1871 | } |
1872 | |
1873 | bool ScriptInterpreterPythonImpl::BreakpointCallbackFunction( |
1874 | void *baton, StoppointCallbackContext *context, user_id_t break_id, |
1875 | user_id_t break_loc_id) { |
1876 | CommandDataPython *bp_option_data = (CommandDataPython *)baton; |
1877 | const char *python_function_name = bp_option_data->script_source.c_str(); |
1878 | |
1879 | if (!context) |
1880 | return true; |
1881 | |
1882 | ExecutionContext exe_ctx(context->exe_ctx_ref); |
1883 | Target *target = exe_ctx.GetTargetPtr(); |
1884 | |
1885 | if (!target) |
1886 | return true; |
1887 | |
1888 | Debugger &debugger = target->GetDebugger(); |
1889 | ScriptInterpreterPythonImpl *python_interpreter = |
1890 | GetPythonInterpreter(debugger); |
1891 | |
1892 | if (!python_interpreter) |
1893 | return true; |
1894 | |
1895 | if (python_function_name && python_function_name[0]) { |
1896 | const StackFrameSP stop_frame_sp(exe_ctx.GetFrameSP()); |
1897 | BreakpointSP breakpoint_sp = target->GetBreakpointByID(break_id); |
1898 | if (breakpoint_sp) { |
1899 | const BreakpointLocationSP bp_loc_sp( |
1900 | breakpoint_sp->FindLocationByID(bp_loc_id: break_loc_id)); |
1901 | |
1902 | if (stop_frame_sp && bp_loc_sp) { |
1903 | bool ret_val = true; |
1904 | { |
1905 | Locker py_lock(python_interpreter, Locker::AcquireLock | |
1906 | Locker::InitSession | |
1907 | Locker::NoSTDIN); |
1908 | Expected<bool> maybe_ret_val = |
1909 | SWIGBridge::LLDBSwigPythonBreakpointCallbackFunction( |
1910 | python_function_name, |
1911 | session_dictionary_name: python_interpreter->m_dictionary_name.c_str(), sb_frame: stop_frame_sp, |
1912 | sb_bp_loc: bp_loc_sp, args_impl: bp_option_data->m_extra_args); |
1913 | |
1914 | if (!maybe_ret_val) { |
1915 | |
1916 | llvm::handleAllErrors( |
1917 | E: maybe_ret_val.takeError(), |
1918 | Handlers: [&](PythonException &E) { |
1919 | *debugger.GetAsyncErrorStream() << E.ReadBacktrace(); |
1920 | }, |
1921 | Handlers: [&](const llvm::ErrorInfoBase &E) { |
1922 | *debugger.GetAsyncErrorStream() << E.message(); |
1923 | }); |
1924 | |
1925 | } else { |
1926 | ret_val = maybe_ret_val.get(); |
1927 | } |
1928 | } |
1929 | return ret_val; |
1930 | } |
1931 | } |
1932 | } |
1933 | // We currently always true so we stop in case anything goes wrong when |
1934 | // trying to call the script function |
1935 | return true; |
1936 | } |
1937 | |
1938 | bool ScriptInterpreterPythonImpl::WatchpointCallbackFunction( |
1939 | void *baton, StoppointCallbackContext *context, user_id_t watch_id) { |
1940 | WatchpointOptions::CommandData *wp_option_data = |
1941 | (WatchpointOptions::CommandData *)baton; |
1942 | const char *python_function_name = wp_option_data->script_source.c_str(); |
1943 | |
1944 | if (!context) |
1945 | return true; |
1946 | |
1947 | ExecutionContext exe_ctx(context->exe_ctx_ref); |
1948 | Target *target = exe_ctx.GetTargetPtr(); |
1949 | |
1950 | if (!target) |
1951 | return true; |
1952 | |
1953 | Debugger &debugger = target->GetDebugger(); |
1954 | ScriptInterpreterPythonImpl *python_interpreter = |
1955 | GetPythonInterpreter(debugger); |
1956 | |
1957 | if (!python_interpreter) |
1958 | return true; |
1959 | |
1960 | if (python_function_name && python_function_name[0]) { |
1961 | const StackFrameSP stop_frame_sp(exe_ctx.GetFrameSP()); |
1962 | WatchpointSP wp_sp = target->GetWatchpointList().FindByID(watchID: watch_id); |
1963 | if (wp_sp) { |
1964 | if (stop_frame_sp && wp_sp) { |
1965 | bool ret_val = true; |
1966 | { |
1967 | Locker py_lock(python_interpreter, Locker::AcquireLock | |
1968 | Locker::InitSession | |
1969 | Locker::NoSTDIN); |
1970 | ret_val = SWIGBridge::LLDBSwigPythonWatchpointCallbackFunction( |
1971 | python_function_name, |
1972 | session_dictionary_name: python_interpreter->m_dictionary_name.c_str(), sb_frame: stop_frame_sp, |
1973 | sb_wp: wp_sp); |
1974 | } |
1975 | return ret_val; |
1976 | } |
1977 | } |
1978 | } |
1979 | // We currently always true so we stop in case anything goes wrong when |
1980 | // trying to call the script function |
1981 | return true; |
1982 | } |
1983 | |
1984 | size_t ScriptInterpreterPythonImpl::CalculateNumChildren( |
1985 | const StructuredData::ObjectSP &implementor_sp, uint32_t max) { |
1986 | if (!implementor_sp) |
1987 | return 0; |
1988 | StructuredData::Generic *generic = implementor_sp->GetAsGeneric(); |
1989 | if (!generic) |
1990 | return 0; |
1991 | auto *implementor = static_cast<PyObject *>(generic->GetValue()); |
1992 | if (!implementor) |
1993 | return 0; |
1994 | |
1995 | size_t ret_val = 0; |
1996 | |
1997 | { |
1998 | Locker py_lock(this, |
1999 | Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); |
2000 | ret_val = SWIGBridge::LLDBSwigPython_CalculateNumChildren(implementor, max); |
2001 | } |
2002 | |
2003 | return ret_val; |
2004 | } |
2005 | |
2006 | lldb::ValueObjectSP ScriptInterpreterPythonImpl::GetChildAtIndex( |
2007 | const StructuredData::ObjectSP &implementor_sp, uint32_t idx) { |
2008 | if (!implementor_sp) |
2009 | return lldb::ValueObjectSP(); |
2010 | |
2011 | StructuredData::Generic *generic = implementor_sp->GetAsGeneric(); |
2012 | if (!generic) |
2013 | return lldb::ValueObjectSP(); |
2014 | auto *implementor = static_cast<PyObject *>(generic->GetValue()); |
2015 | if (!implementor) |
2016 | return lldb::ValueObjectSP(); |
2017 | |
2018 | lldb::ValueObjectSP ret_val; |
2019 | { |
2020 | Locker py_lock(this, |
2021 | Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); |
2022 | PyObject *child_ptr = |
2023 | SWIGBridge::LLDBSwigPython_GetChildAtIndex(implementor, idx); |
2024 | if (child_ptr != nullptr && child_ptr != Py_None) { |
2025 | lldb::SBValue *sb_value_ptr = |
2026 | (lldb::SBValue *)LLDBSWIGPython_CastPyObjectToSBValue(data: child_ptr); |
2027 | if (sb_value_ptr == nullptr) |
2028 | Py_XDECREF(child_ptr); |
2029 | else |
2030 | ret_val = SWIGBridge::LLDBSWIGPython_GetValueObjectSPFromSBValue( |
2031 | data: sb_value_ptr); |
2032 | } else { |
2033 | Py_XDECREF(child_ptr); |
2034 | } |
2035 | } |
2036 | |
2037 | return ret_val; |
2038 | } |
2039 | |
2040 | llvm::Expected<int> ScriptInterpreterPythonImpl::GetIndexOfChildWithName( |
2041 | const StructuredData::ObjectSP &implementor_sp, const char *child_name) { |
2042 | if (!implementor_sp) |
2043 | return llvm::createStringError(Fmt: "Type has no child named '%s'" , Vals: child_name); |
2044 | |
2045 | StructuredData::Generic *generic = implementor_sp->GetAsGeneric(); |
2046 | if (!generic) |
2047 | return llvm::createStringError(Fmt: "Type has no child named '%s'" , Vals: child_name); |
2048 | auto *implementor = static_cast<PyObject *>(generic->GetValue()); |
2049 | if (!implementor) |
2050 | return llvm::createStringError(Fmt: "Type has no child named '%s'" , Vals: child_name); |
2051 | |
2052 | int ret_val = INT32_MAX; |
2053 | |
2054 | { |
2055 | Locker py_lock(this, |
2056 | Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); |
2057 | ret_val = SWIGBridge::LLDBSwigPython_GetIndexOfChildWithName(implementor, |
2058 | child_name); |
2059 | } |
2060 | |
2061 | if (ret_val == INT32_MAX) |
2062 | return llvm::createStringError(Fmt: "Type has no child named '%s'" , Vals: child_name); |
2063 | return ret_val; |
2064 | } |
2065 | |
2066 | bool ScriptInterpreterPythonImpl::UpdateSynthProviderInstance( |
2067 | const StructuredData::ObjectSP &implementor_sp) { |
2068 | bool ret_val = false; |
2069 | |
2070 | if (!implementor_sp) |
2071 | return ret_val; |
2072 | |
2073 | StructuredData::Generic *generic = implementor_sp->GetAsGeneric(); |
2074 | if (!generic) |
2075 | return ret_val; |
2076 | auto *implementor = static_cast<PyObject *>(generic->GetValue()); |
2077 | if (!implementor) |
2078 | return ret_val; |
2079 | |
2080 | { |
2081 | Locker py_lock(this, |
2082 | Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); |
2083 | ret_val = |
2084 | SWIGBridge::LLDBSwigPython_UpdateSynthProviderInstance(implementor); |
2085 | } |
2086 | |
2087 | return ret_val; |
2088 | } |
2089 | |
2090 | bool ScriptInterpreterPythonImpl::MightHaveChildrenSynthProviderInstance( |
2091 | const StructuredData::ObjectSP &implementor_sp) { |
2092 | bool ret_val = false; |
2093 | |
2094 | if (!implementor_sp) |
2095 | return ret_val; |
2096 | |
2097 | StructuredData::Generic *generic = implementor_sp->GetAsGeneric(); |
2098 | if (!generic) |
2099 | return ret_val; |
2100 | auto *implementor = static_cast<PyObject *>(generic->GetValue()); |
2101 | if (!implementor) |
2102 | return ret_val; |
2103 | |
2104 | { |
2105 | Locker py_lock(this, |
2106 | Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); |
2107 | ret_val = SWIGBridge::LLDBSwigPython_MightHaveChildrenSynthProviderInstance( |
2108 | implementor); |
2109 | } |
2110 | |
2111 | return ret_val; |
2112 | } |
2113 | |
2114 | lldb::ValueObjectSP ScriptInterpreterPythonImpl::GetSyntheticValue( |
2115 | const StructuredData::ObjectSP &implementor_sp) { |
2116 | lldb::ValueObjectSP ret_val(nullptr); |
2117 | |
2118 | if (!implementor_sp) |
2119 | return ret_val; |
2120 | |
2121 | StructuredData::Generic *generic = implementor_sp->GetAsGeneric(); |
2122 | if (!generic) |
2123 | return ret_val; |
2124 | auto *implementor = static_cast<PyObject *>(generic->GetValue()); |
2125 | if (!implementor) |
2126 | return ret_val; |
2127 | |
2128 | { |
2129 | Locker py_lock(this, |
2130 | Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); |
2131 | PyObject *child_ptr = |
2132 | SWIGBridge::LLDBSwigPython_GetValueSynthProviderInstance(implementor); |
2133 | if (child_ptr != nullptr && child_ptr != Py_None) { |
2134 | lldb::SBValue *sb_value_ptr = |
2135 | (lldb::SBValue *)LLDBSWIGPython_CastPyObjectToSBValue(data: child_ptr); |
2136 | if (sb_value_ptr == nullptr) |
2137 | Py_XDECREF(child_ptr); |
2138 | else |
2139 | ret_val = SWIGBridge::LLDBSWIGPython_GetValueObjectSPFromSBValue( |
2140 | data: sb_value_ptr); |
2141 | } else { |
2142 | Py_XDECREF(child_ptr); |
2143 | } |
2144 | } |
2145 | |
2146 | return ret_val; |
2147 | } |
2148 | |
2149 | ConstString ScriptInterpreterPythonImpl::GetSyntheticTypeName( |
2150 | const StructuredData::ObjectSP &implementor_sp) { |
2151 | Locker py_lock(this, |
2152 | Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); |
2153 | |
2154 | if (!implementor_sp) |
2155 | return {}; |
2156 | |
2157 | StructuredData::Generic *generic = implementor_sp->GetAsGeneric(); |
2158 | if (!generic) |
2159 | return {}; |
2160 | |
2161 | PythonObject implementor(PyRefType::Borrowed, |
2162 | (PyObject *)generic->GetValue()); |
2163 | if (!implementor.IsAllocated()) |
2164 | return {}; |
2165 | |
2166 | llvm::Expected<PythonObject> expected_py_return = |
2167 | implementor.CallMethod(name: "get_type_name" ); |
2168 | |
2169 | if (!expected_py_return) { |
2170 | llvm::consumeError(Err: expected_py_return.takeError()); |
2171 | return {}; |
2172 | } |
2173 | |
2174 | PythonObject py_return = std::move(expected_py_return.get()); |
2175 | if (!py_return.IsAllocated() || !PythonString::Check(py_obj: py_return.get())) |
2176 | return {}; |
2177 | |
2178 | PythonString type_name(PyRefType::Borrowed, py_return.get()); |
2179 | return ConstString(type_name.GetString()); |
2180 | } |
2181 | |
2182 | bool ScriptInterpreterPythonImpl::RunScriptFormatKeyword( |
2183 | const char *impl_function, Process *process, std::string &output, |
2184 | Status &error) { |
2185 | bool ret_val; |
2186 | if (!process) { |
2187 | error = Status::FromErrorString(str: "no process" ); |
2188 | return false; |
2189 | } |
2190 | if (!impl_function || !impl_function[0]) { |
2191 | error = Status::FromErrorString(str: "no function to execute" ); |
2192 | return false; |
2193 | } |
2194 | |
2195 | { |
2196 | Locker py_lock(this, |
2197 | Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); |
2198 | ret_val = SWIGBridge::LLDBSWIGPythonRunScriptKeywordProcess( |
2199 | python_function_name: impl_function, session_dictionary_name: m_dictionary_name.c_str(), process: process->shared_from_this(), |
2200 | output); |
2201 | if (!ret_val) |
2202 | error = Status::FromErrorString(str: "python script evaluation failed" ); |
2203 | } |
2204 | return ret_val; |
2205 | } |
2206 | |
2207 | bool ScriptInterpreterPythonImpl::RunScriptFormatKeyword( |
2208 | const char *impl_function, Thread *thread, std::string &output, |
2209 | Status &error) { |
2210 | if (!thread) { |
2211 | error = Status::FromErrorString(str: "no thread" ); |
2212 | return false; |
2213 | } |
2214 | if (!impl_function || !impl_function[0]) { |
2215 | error = Status::FromErrorString(str: "no function to execute" ); |
2216 | return false; |
2217 | } |
2218 | |
2219 | Locker py_lock(this, |
2220 | Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); |
2221 | if (std::optional<std::string> result = |
2222 | SWIGBridge::LLDBSWIGPythonRunScriptKeywordThread( |
2223 | python_function_name: impl_function, session_dictionary_name: m_dictionary_name.c_str(), |
2224 | thread: thread->shared_from_this())) { |
2225 | output = std::move(*result); |
2226 | return true; |
2227 | } |
2228 | error = Status::FromErrorString(str: "python script evaluation failed" ); |
2229 | return false; |
2230 | } |
2231 | |
2232 | bool ScriptInterpreterPythonImpl::RunScriptFormatKeyword( |
2233 | const char *impl_function, Target *target, std::string &output, |
2234 | Status &error) { |
2235 | bool ret_val; |
2236 | if (!target) { |
2237 | error = Status::FromErrorString(str: "no thread" ); |
2238 | return false; |
2239 | } |
2240 | if (!impl_function || !impl_function[0]) { |
2241 | error = Status::FromErrorString(str: "no function to execute" ); |
2242 | return false; |
2243 | } |
2244 | |
2245 | { |
2246 | TargetSP target_sp(target->shared_from_this()); |
2247 | Locker py_lock(this, |
2248 | Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); |
2249 | ret_val = SWIGBridge::LLDBSWIGPythonRunScriptKeywordTarget( |
2250 | python_function_name: impl_function, session_dictionary_name: m_dictionary_name.c_str(), target: target_sp, output); |
2251 | if (!ret_val) |
2252 | error = Status::FromErrorString(str: "python script evaluation failed" ); |
2253 | } |
2254 | return ret_val; |
2255 | } |
2256 | |
2257 | bool ScriptInterpreterPythonImpl::RunScriptFormatKeyword( |
2258 | const char *impl_function, StackFrame *frame, std::string &output, |
2259 | Status &error) { |
2260 | if (!frame) { |
2261 | error = Status::FromErrorString(str: "no frame" ); |
2262 | return false; |
2263 | } |
2264 | if (!impl_function || !impl_function[0]) { |
2265 | error = Status::FromErrorString(str: "no function to execute" ); |
2266 | return false; |
2267 | } |
2268 | |
2269 | Locker py_lock(this, |
2270 | Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); |
2271 | if (std::optional<std::string> result = |
2272 | SWIGBridge::LLDBSWIGPythonRunScriptKeywordFrame( |
2273 | python_function_name: impl_function, session_dictionary_name: m_dictionary_name.c_str(), |
2274 | frame: frame->shared_from_this())) { |
2275 | output = std::move(*result); |
2276 | return true; |
2277 | } |
2278 | error = Status::FromErrorString(str: "python script evaluation failed" ); |
2279 | return false; |
2280 | } |
2281 | |
2282 | bool ScriptInterpreterPythonImpl::RunScriptFormatKeyword( |
2283 | const char *impl_function, ValueObject *value, std::string &output, |
2284 | Status &error) { |
2285 | bool ret_val; |
2286 | if (!value) { |
2287 | error = Status::FromErrorString(str: "no value" ); |
2288 | return false; |
2289 | } |
2290 | if (!impl_function || !impl_function[0]) { |
2291 | error = Status::FromErrorString(str: "no function to execute" ); |
2292 | return false; |
2293 | } |
2294 | |
2295 | { |
2296 | Locker py_lock(this, |
2297 | Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); |
2298 | ret_val = SWIGBridge::LLDBSWIGPythonRunScriptKeywordValue( |
2299 | python_function_name: impl_function, session_dictionary_name: m_dictionary_name.c_str(), value: value->GetSP(), output); |
2300 | if (!ret_val) |
2301 | error = Status::FromErrorString(str: "python script evaluation failed" ); |
2302 | } |
2303 | return ret_val; |
2304 | } |
2305 | |
2306 | uint64_t replace_all(std::string &str, const std::string &oldStr, |
2307 | const std::string &newStr) { |
2308 | size_t pos = 0; |
2309 | uint64_t matches = 0; |
2310 | while ((pos = str.find(str: oldStr, pos: pos)) != std::string::npos) { |
2311 | matches++; |
2312 | str.replace(pos: pos, n: oldStr.length(), str: newStr); |
2313 | pos += newStr.length(); |
2314 | } |
2315 | return matches; |
2316 | } |
2317 | |
2318 | bool ScriptInterpreterPythonImpl::LoadScriptingModule( |
2319 | const char *pathname, const LoadScriptOptions &options, |
2320 | lldb_private::Status &error, StructuredData::ObjectSP *module_sp, |
2321 | FileSpec , lldb::TargetSP target_sp) { |
2322 | namespace fs = llvm::sys::fs; |
2323 | namespace path = llvm::sys::path; |
2324 | |
2325 | ExecuteScriptOptions exc_options = ExecuteScriptOptions() |
2326 | .SetEnableIO(!options.GetSilent()) |
2327 | .SetSetLLDBGlobals(false); |
2328 | |
2329 | if (!pathname || !pathname[0]) { |
2330 | error = Status::FromErrorString(str: "empty path" ); |
2331 | return false; |
2332 | } |
2333 | |
2334 | llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>> |
2335 | io_redirect_or_error = ScriptInterpreterIORedirect::Create( |
2336 | enable_io: exc_options.GetEnableIO(), debugger&: m_debugger, /*result=*/nullptr); |
2337 | |
2338 | if (!io_redirect_or_error) { |
2339 | error = Status::FromError(error: io_redirect_or_error.takeError()); |
2340 | return false; |
2341 | } |
2342 | |
2343 | ScriptInterpreterIORedirect &io_redirect = **io_redirect_or_error; |
2344 | |
2345 | // Before executing Python code, lock the GIL. |
2346 | Locker py_lock(this, |
2347 | Locker::AcquireLock | |
2348 | (options.GetInitSession() ? Locker::InitSession : 0) | |
2349 | Locker::NoSTDIN, |
2350 | Locker::FreeAcquiredLock | |
2351 | (options.GetInitSession() ? Locker::TearDownSession : 0), |
2352 | io_redirect.GetInputFile(), io_redirect.GetOutputFile(), |
2353 | io_redirect.GetErrorFile()); |
2354 | |
2355 | auto ExtendSysPath = [&](std::string directory) -> llvm::Error { |
2356 | if (directory.empty()) { |
2357 | return llvm::createStringError(Fmt: "invalid directory name" ); |
2358 | } |
2359 | |
2360 | replace_all(str&: directory, oldStr: "\\" , newStr: "\\\\" ); |
2361 | replace_all(str&: directory, oldStr: "'" , newStr: "\\'" ); |
2362 | |
2363 | // Make sure that Python has "directory" in the search path. |
2364 | StreamString command_stream; |
2365 | command_stream.Printf(format: "if not (sys.path.__contains__('%s')):\n " |
2366 | "sys.path.insert(1,'%s');\n\n" , |
2367 | directory.c_str(), directory.c_str()); |
2368 | bool syspath_retval = |
2369 | ExecuteMultipleLines(in_string: command_stream.GetData(), options: exc_options).Success(); |
2370 | if (!syspath_retval) |
2371 | return llvm::createStringError(Fmt: "Python sys.path handling failed" ); |
2372 | |
2373 | return llvm::Error::success(); |
2374 | }; |
2375 | |
2376 | std::string module_name(pathname); |
2377 | bool possible_package = false; |
2378 | |
2379 | if (extra_search_dir) { |
2380 | if (llvm::Error e = ExtendSysPath(extra_search_dir.GetPath())) { |
2381 | error = Status::FromError(error: std::move(e)); |
2382 | return false; |
2383 | } |
2384 | } else { |
2385 | FileSpec module_file(pathname); |
2386 | FileSystem::Instance().Resolve(file_spec&: module_file); |
2387 | |
2388 | fs::file_status st; |
2389 | std::error_code ec = status(path: module_file.GetPath(), result&: st); |
2390 | |
2391 | if (ec || st.type() == fs::file_type::status_error || |
2392 | st.type() == fs::file_type::type_unknown || |
2393 | st.type() == fs::file_type::file_not_found) { |
2394 | // if not a valid file of any sort, check if it might be a filename still |
2395 | // dot can't be used but / and \ can, and if either is found, reject |
2396 | if (strchr(s: pathname, c: '\\') || strchr(s: pathname, c: '/')) { |
2397 | error = Status::FromErrorStringWithFormatv(format: "invalid pathname '{0}'" , |
2398 | args&: pathname); |
2399 | return false; |
2400 | } |
2401 | // Not a filename, probably a package of some sort, let it go through. |
2402 | possible_package = true; |
2403 | } else if (is_directory(status: st) || is_regular_file(status: st)) { |
2404 | if (module_file.GetDirectory().IsEmpty()) { |
2405 | error = Status::FromErrorStringWithFormatv( |
2406 | format: "invalid directory name '{0}'" , args&: pathname); |
2407 | return false; |
2408 | } |
2409 | if (llvm::Error e = |
2410 | ExtendSysPath(module_file.GetDirectory().GetCString())) { |
2411 | error = Status::FromError(error: std::move(e)); |
2412 | return false; |
2413 | } |
2414 | module_name = module_file.GetFilename().GetCString(); |
2415 | } else { |
2416 | error = Status::FromErrorString( |
2417 | str: "no known way to import this module specification" ); |
2418 | return false; |
2419 | } |
2420 | } |
2421 | |
2422 | // Strip .py or .pyc extension |
2423 | llvm::StringRef extension = llvm::sys::path::extension(path: module_name); |
2424 | if (!extension.empty()) { |
2425 | if (extension == ".py" ) |
2426 | module_name.resize(n: module_name.length() - 3); |
2427 | else if (extension == ".pyc" ) |
2428 | module_name.resize(n: module_name.length() - 4); |
2429 | } |
2430 | |
2431 | if (!possible_package && module_name.find(c: '.') != llvm::StringRef::npos) { |
2432 | error = Status::FromErrorStringWithFormat( |
2433 | format: "Python does not allow dots in module names: %s" , module_name.c_str()); |
2434 | return false; |
2435 | } |
2436 | |
2437 | if (module_name.find(c: '-') != llvm::StringRef::npos) { |
2438 | error = Status::FromErrorStringWithFormat( |
2439 | format: "Python discourages dashes in module names: %s" , module_name.c_str()); |
2440 | return false; |
2441 | } |
2442 | |
2443 | // Check if the module is already imported. |
2444 | StreamString command_stream; |
2445 | command_stream.Clear(); |
2446 | command_stream.Printf(format: "sys.modules.__contains__('%s')" , module_name.c_str()); |
2447 | bool does_contain = false; |
2448 | // This call will succeed if the module was ever imported in any Debugger in |
2449 | // the lifetime of the process in which this LLDB framework is living. |
2450 | const bool does_contain_executed = ExecuteOneLineWithReturn( |
2451 | in_string: command_stream.GetData(), |
2452 | return_type: ScriptInterpreterPythonImpl::eScriptReturnTypeBool, ret_value: &does_contain, |
2453 | options: exc_options); |
2454 | |
2455 | const bool was_imported_globally = does_contain_executed && does_contain; |
2456 | const bool was_imported_locally = |
2457 | GetSessionDictionary() |
2458 | .GetItemForKey(key: PythonString(module_name)) |
2459 | .IsAllocated(); |
2460 | |
2461 | // now actually do the import |
2462 | command_stream.Clear(); |
2463 | |
2464 | if (was_imported_globally || was_imported_locally) { |
2465 | if (!was_imported_locally) |
2466 | command_stream.Printf(format: "import %s ; reload_module(%s)" , |
2467 | module_name.c_str(), module_name.c_str()); |
2468 | else |
2469 | command_stream.Printf(format: "reload_module(%s)" , module_name.c_str()); |
2470 | } else |
2471 | command_stream.Printf(format: "import %s" , module_name.c_str()); |
2472 | |
2473 | error = ExecuteMultipleLines(in_string: command_stream.GetData(), options: exc_options); |
2474 | if (error.Fail()) |
2475 | return false; |
2476 | |
2477 | // if we are here, everything worked |
2478 | // call __lldb_init_module(debugger,dict) |
2479 | if (!SWIGBridge::LLDBSwigPythonCallModuleInit( |
2480 | python_module_name: module_name.c_str(), session_dictionary_name: m_dictionary_name.c_str(), |
2481 | debugger: m_debugger.shared_from_this())) { |
2482 | error = Status::FromErrorString(str: "calling __lldb_init_module failed" ); |
2483 | return false; |
2484 | } |
2485 | |
2486 | if (module_sp) { |
2487 | // everything went just great, now set the module object |
2488 | command_stream.Clear(); |
2489 | command_stream.Printf(format: "%s" , module_name.c_str()); |
2490 | void *module_pyobj = nullptr; |
2491 | if (ExecuteOneLineWithReturn( |
2492 | in_string: command_stream.GetData(), |
2493 | return_type: ScriptInterpreter::eScriptReturnTypeOpaqueObject, ret_value: &module_pyobj, |
2494 | options: exc_options) && |
2495 | module_pyobj) |
2496 | *module_sp = std::make_shared<StructuredPythonObject>(args: PythonObject( |
2497 | PyRefType::Owned, static_cast<PyObject *>(module_pyobj))); |
2498 | } |
2499 | |
2500 | // Finally, if we got a target passed in, then we should tell the new module |
2501 | // about this target: |
2502 | if (target_sp) |
2503 | return SWIGBridge::LLDBSwigPythonCallModuleNewTarget( |
2504 | python_module_name: module_name.c_str(), session_dictionary_name: m_dictionary_name.c_str(), target: target_sp); |
2505 | |
2506 | return true; |
2507 | } |
2508 | |
2509 | bool ScriptInterpreterPythonImpl::IsReservedWord(const char *word) { |
2510 | if (!word || !word[0]) |
2511 | return false; |
2512 | |
2513 | llvm::StringRef word_sr(word); |
2514 | |
2515 | // filter out a few characters that would just confuse us and that are |
2516 | // clearly not keyword material anyway |
2517 | if (word_sr.find(C: '"') != llvm::StringRef::npos || |
2518 | word_sr.find(C: '\'') != llvm::StringRef::npos) |
2519 | return false; |
2520 | |
2521 | StreamString command_stream; |
2522 | command_stream.Printf(format: "keyword.iskeyword('%s')" , word); |
2523 | bool result; |
2524 | ExecuteScriptOptions options; |
2525 | options.SetEnableIO(false); |
2526 | options.SetMaskoutErrors(true); |
2527 | options.SetSetLLDBGlobals(false); |
2528 | if (ExecuteOneLineWithReturn(in_string: command_stream.GetData(), |
2529 | return_type: ScriptInterpreter::eScriptReturnTypeBool, |
2530 | ret_value: &result, options)) |
2531 | return result; |
2532 | return false; |
2533 | } |
2534 | |
2535 | ScriptInterpreterPythonImpl::SynchronicityHandler::SynchronicityHandler( |
2536 | lldb::DebuggerSP debugger_sp, ScriptedCommandSynchronicity synchro) |
2537 | : m_debugger_sp(debugger_sp), m_synch_wanted(synchro), |
2538 | m_old_asynch(debugger_sp->GetAsyncExecution()) { |
2539 | if (m_synch_wanted == eScriptedCommandSynchronicitySynchronous) |
2540 | m_debugger_sp->SetAsyncExecution(false); |
2541 | else if (m_synch_wanted == eScriptedCommandSynchronicityAsynchronous) |
2542 | m_debugger_sp->SetAsyncExecution(true); |
2543 | } |
2544 | |
2545 | ScriptInterpreterPythonImpl::SynchronicityHandler::~SynchronicityHandler() { |
2546 | if (m_synch_wanted != eScriptedCommandSynchronicityCurrentValue) |
2547 | m_debugger_sp->SetAsyncExecution(m_old_asynch); |
2548 | } |
2549 | |
2550 | bool ScriptInterpreterPythonImpl::RunScriptBasedCommand( |
2551 | const char *impl_function, llvm::StringRef args, |
2552 | ScriptedCommandSynchronicity synchronicity, |
2553 | lldb_private::CommandReturnObject &cmd_retobj, Status &error, |
2554 | const lldb_private::ExecutionContext &exe_ctx) { |
2555 | if (!impl_function) { |
2556 | error = Status::FromErrorString(str: "no function to execute" ); |
2557 | return false; |
2558 | } |
2559 | |
2560 | lldb::DebuggerSP debugger_sp = m_debugger.shared_from_this(); |
2561 | lldb::ExecutionContextRefSP exe_ctx_ref_sp(new ExecutionContextRef(exe_ctx)); |
2562 | |
2563 | if (!debugger_sp.get()) { |
2564 | error = Status::FromErrorString(str: "invalid Debugger pointer" ); |
2565 | return false; |
2566 | } |
2567 | |
2568 | bool ret_val = false; |
2569 | |
2570 | { |
2571 | Locker py_lock(this, |
2572 | Locker::AcquireLock | Locker::InitSession | |
2573 | (cmd_retobj.GetInteractive() ? 0 : Locker::NoSTDIN), |
2574 | Locker::FreeLock | Locker::TearDownSession); |
2575 | |
2576 | SynchronicityHandler synch_handler(debugger_sp, synchronicity); |
2577 | |
2578 | std::string args_str = args.str(); |
2579 | ret_val = SWIGBridge::LLDBSwigPythonCallCommand( |
2580 | python_function_name: impl_function, session_dictionary_name: m_dictionary_name.c_str(), debugger: debugger_sp, args: args_str.c_str(), |
2581 | cmd_retobj, exe_ctx_ref_sp); |
2582 | } |
2583 | |
2584 | if (!ret_val) |
2585 | error = Status::FromErrorString(str: "unable to execute script function" ); |
2586 | else if (cmd_retobj.GetStatus() == eReturnStatusFailed) |
2587 | return false; |
2588 | |
2589 | error.Clear(); |
2590 | return ret_val; |
2591 | } |
2592 | |
2593 | bool ScriptInterpreterPythonImpl::RunScriptBasedCommand( |
2594 | StructuredData::GenericSP impl_obj_sp, llvm::StringRef args, |
2595 | ScriptedCommandSynchronicity synchronicity, |
2596 | lldb_private::CommandReturnObject &cmd_retobj, Status &error, |
2597 | const lldb_private::ExecutionContext &exe_ctx) { |
2598 | if (!impl_obj_sp || !impl_obj_sp->IsValid()) { |
2599 | error = Status::FromErrorString(str: "no function to execute" ); |
2600 | return false; |
2601 | } |
2602 | |
2603 | lldb::DebuggerSP debugger_sp = m_debugger.shared_from_this(); |
2604 | lldb::ExecutionContextRefSP exe_ctx_ref_sp(new ExecutionContextRef(exe_ctx)); |
2605 | |
2606 | if (!debugger_sp.get()) { |
2607 | error = Status::FromErrorString(str: "invalid Debugger pointer" ); |
2608 | return false; |
2609 | } |
2610 | |
2611 | bool ret_val = false; |
2612 | |
2613 | { |
2614 | Locker py_lock(this, |
2615 | Locker::AcquireLock | Locker::InitSession | |
2616 | (cmd_retobj.GetInteractive() ? 0 : Locker::NoSTDIN), |
2617 | Locker::FreeLock | Locker::TearDownSession); |
2618 | |
2619 | SynchronicityHandler synch_handler(debugger_sp, synchronicity); |
2620 | |
2621 | std::string args_str = args.str(); |
2622 | ret_val = SWIGBridge::LLDBSwigPythonCallCommandObject( |
2623 | implementor: static_cast<PyObject *>(impl_obj_sp->GetValue()), debugger: debugger_sp, |
2624 | args: args_str.c_str(), cmd_retobj, exe_ctx_ref_sp); |
2625 | } |
2626 | |
2627 | if (!ret_val) |
2628 | error = Status::FromErrorString(str: "unable to execute script function" ); |
2629 | else if (cmd_retobj.GetStatus() == eReturnStatusFailed) |
2630 | return false; |
2631 | |
2632 | error.Clear(); |
2633 | return ret_val; |
2634 | } |
2635 | |
2636 | bool ScriptInterpreterPythonImpl::RunScriptBasedParsedCommand( |
2637 | StructuredData::GenericSP impl_obj_sp, Args &args, |
2638 | ScriptedCommandSynchronicity synchronicity, |
2639 | lldb_private::CommandReturnObject &cmd_retobj, Status &error, |
2640 | const lldb_private::ExecutionContext &exe_ctx) { |
2641 | if (!impl_obj_sp || !impl_obj_sp->IsValid()) { |
2642 | error = Status::FromErrorString(str: "no function to execute" ); |
2643 | return false; |
2644 | } |
2645 | |
2646 | lldb::DebuggerSP debugger_sp = m_debugger.shared_from_this(); |
2647 | lldb::ExecutionContextRefSP exe_ctx_ref_sp(new ExecutionContextRef(exe_ctx)); |
2648 | |
2649 | if (!debugger_sp.get()) { |
2650 | error = Status::FromErrorString(str: "invalid Debugger pointer" ); |
2651 | return false; |
2652 | } |
2653 | |
2654 | bool ret_val = false; |
2655 | |
2656 | { |
2657 | Locker py_lock(this, |
2658 | Locker::AcquireLock | Locker::InitSession | |
2659 | (cmd_retobj.GetInteractive() ? 0 : Locker::NoSTDIN), |
2660 | Locker::FreeLock | Locker::TearDownSession); |
2661 | |
2662 | SynchronicityHandler synch_handler(debugger_sp, synchronicity); |
2663 | |
2664 | StructuredData::ArraySP args_arr_sp(new StructuredData::Array()); |
2665 | |
2666 | for (const Args::ArgEntry &entry : args) { |
2667 | args_arr_sp->AddStringItem(value: entry.ref()); |
2668 | } |
2669 | StructuredDataImpl args_impl(args_arr_sp); |
2670 | |
2671 | ret_val = SWIGBridge::LLDBSwigPythonCallParsedCommandObject( |
2672 | implementor: static_cast<PyObject *>(impl_obj_sp->GetValue()), debugger: debugger_sp, |
2673 | args_impl, cmd_retobj, exe_ctx_ref_sp); |
2674 | } |
2675 | |
2676 | if (!ret_val) |
2677 | error = Status::FromErrorString(str: "unable to execute script function" ); |
2678 | else if (cmd_retobj.GetStatus() == eReturnStatusFailed) |
2679 | return false; |
2680 | |
2681 | error.Clear(); |
2682 | return ret_val; |
2683 | } |
2684 | |
2685 | std::optional<std::string> |
2686 | ScriptInterpreterPythonImpl::GetRepeatCommandForScriptedCommand( |
2687 | StructuredData::GenericSP impl_obj_sp, Args &args) { |
2688 | if (!impl_obj_sp || !impl_obj_sp->IsValid()) |
2689 | return std::nullopt; |
2690 | |
2691 | lldb::DebuggerSP debugger_sp = m_debugger.shared_from_this(); |
2692 | |
2693 | if (!debugger_sp.get()) |
2694 | return std::nullopt; |
2695 | |
2696 | std::optional<std::string> ret_val; |
2697 | |
2698 | { |
2699 | Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, |
2700 | Locker::FreeLock); |
2701 | |
2702 | StructuredData::ArraySP args_arr_sp(new StructuredData::Array()); |
2703 | |
2704 | // For scripting commands, we send the command string: |
2705 | std::string command; |
2706 | args.GetQuotedCommandString(command); |
2707 | ret_val = SWIGBridge::LLDBSwigPythonGetRepeatCommandForScriptedCommand( |
2708 | implementor: static_cast<PyObject *>(impl_obj_sp->GetValue()), command); |
2709 | } |
2710 | return ret_val; |
2711 | } |
2712 | |
2713 | StructuredData::DictionarySP |
2714 | ScriptInterpreterPythonImpl::HandleArgumentCompletionForScriptedCommand( |
2715 | StructuredData::GenericSP impl_obj_sp, std::vector<llvm::StringRef> &args, |
2716 | size_t args_pos, size_t char_in_arg) { |
2717 | StructuredData::DictionarySP completion_dict_sp; |
2718 | if (!impl_obj_sp || !impl_obj_sp->IsValid()) |
2719 | return completion_dict_sp; |
2720 | |
2721 | { |
2722 | Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, |
2723 | Locker::FreeLock); |
2724 | |
2725 | completion_dict_sp = |
2726 | SWIGBridge::LLDBSwigPythonHandleArgumentCompletionForScriptedCommand( |
2727 | implementor: static_cast<PyObject *>(impl_obj_sp->GetValue()), args_impl&: args, args_pos, |
2728 | pos_in_arg: char_in_arg); |
2729 | } |
2730 | return completion_dict_sp; |
2731 | } |
2732 | |
2733 | StructuredData::DictionarySP |
2734 | ScriptInterpreterPythonImpl::HandleOptionArgumentCompletionForScriptedCommand( |
2735 | StructuredData::GenericSP impl_obj_sp, llvm::StringRef &long_option, |
2736 | size_t char_in_arg) { |
2737 | StructuredData::DictionarySP completion_dict_sp; |
2738 | if (!impl_obj_sp || !impl_obj_sp->IsValid()) |
2739 | return completion_dict_sp; |
2740 | |
2741 | { |
2742 | Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, |
2743 | Locker::FreeLock); |
2744 | |
2745 | completion_dict_sp = SWIGBridge:: |
2746 | LLDBSwigPythonHandleOptionArgumentCompletionForScriptedCommand( |
2747 | implementor: static_cast<PyObject *>(impl_obj_sp->GetValue()), long_option, |
2748 | pos_in_arg: char_in_arg); |
2749 | } |
2750 | return completion_dict_sp; |
2751 | } |
2752 | |
2753 | /// In Python, a special attribute __doc__ contains the docstring for an object |
2754 | /// (function, method, class, ...) if any is defined Otherwise, the attribute's |
2755 | /// value is None. |
2756 | bool ScriptInterpreterPythonImpl::GetDocumentationForItem(const char *item, |
2757 | std::string &dest) { |
2758 | dest.clear(); |
2759 | |
2760 | if (!item || !*item) |
2761 | return false; |
2762 | |
2763 | std::string command(item); |
2764 | command += ".__doc__" ; |
2765 | |
2766 | // Python is going to point this to valid data if ExecuteOneLineWithReturn |
2767 | // returns successfully. |
2768 | char *result_ptr = nullptr; |
2769 | |
2770 | if (ExecuteOneLineWithReturn( |
2771 | in_string: command, return_type: ScriptInterpreter::eScriptReturnTypeCharStrOrNone, |
2772 | ret_value: &result_ptr, options: ExecuteScriptOptions().SetEnableIO(false))) { |
2773 | if (result_ptr) |
2774 | dest.assign(s: result_ptr); |
2775 | return true; |
2776 | } |
2777 | |
2778 | StreamString str_stream; |
2779 | str_stream << "Function " << item |
2780 | << " was not found. Containing module might be missing." ; |
2781 | dest = std::string(str_stream.GetString()); |
2782 | |
2783 | return false; |
2784 | } |
2785 | |
2786 | bool ScriptInterpreterPythonImpl::GetShortHelpForCommandObject( |
2787 | StructuredData::GenericSP cmd_obj_sp, std::string &dest) { |
2788 | dest.clear(); |
2789 | |
2790 | Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); |
2791 | |
2792 | if (!cmd_obj_sp) |
2793 | return false; |
2794 | |
2795 | PythonObject implementor(PyRefType::Borrowed, |
2796 | (PyObject *)cmd_obj_sp->GetValue()); |
2797 | |
2798 | if (!implementor.IsAllocated()) |
2799 | return false; |
2800 | |
2801 | llvm::Expected<PythonObject> expected_py_return = |
2802 | implementor.CallMethod(name: "get_short_help" ); |
2803 | |
2804 | if (!expected_py_return) { |
2805 | llvm::consumeError(Err: expected_py_return.takeError()); |
2806 | return false; |
2807 | } |
2808 | |
2809 | PythonObject py_return = std::move(expected_py_return.get()); |
2810 | |
2811 | if (py_return.IsAllocated() && PythonString::Check(py_obj: py_return.get())) { |
2812 | PythonString py_string(PyRefType::Borrowed, py_return.get()); |
2813 | llvm::StringRef return_data(py_string.GetString()); |
2814 | dest.assign(s: return_data.data(), n: return_data.size()); |
2815 | return true; |
2816 | } |
2817 | |
2818 | return false; |
2819 | } |
2820 | |
2821 | uint32_t ScriptInterpreterPythonImpl::GetFlagsForCommandObject( |
2822 | StructuredData::GenericSP cmd_obj_sp) { |
2823 | uint32_t result = 0; |
2824 | |
2825 | Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); |
2826 | |
2827 | static char callee_name[] = "get_flags" ; |
2828 | |
2829 | if (!cmd_obj_sp) |
2830 | return result; |
2831 | |
2832 | PythonObject implementor(PyRefType::Borrowed, |
2833 | (PyObject *)cmd_obj_sp->GetValue()); |
2834 | |
2835 | if (!implementor.IsAllocated()) |
2836 | return result; |
2837 | |
2838 | PythonObject pmeth(PyRefType::Owned, |
2839 | PyObject_GetAttrString(implementor.get(), callee_name)); |
2840 | |
2841 | if (PyErr_Occurred()) |
2842 | PyErr_Clear(); |
2843 | |
2844 | if (!pmeth.IsAllocated()) |
2845 | return result; |
2846 | |
2847 | if (PyCallable_Check(pmeth.get()) == 0) { |
2848 | if (PyErr_Occurred()) |
2849 | PyErr_Clear(); |
2850 | return result; |
2851 | } |
2852 | |
2853 | if (PyErr_Occurred()) |
2854 | PyErr_Clear(); |
2855 | |
2856 | long long py_return = unwrapOrSetPythonException( |
2857 | expected: As<long long>(obj: implementor.CallMethod(name: callee_name))); |
2858 | |
2859 | // if it fails, print the error but otherwise go on |
2860 | if (PyErr_Occurred()) { |
2861 | PyErr_Print(); |
2862 | PyErr_Clear(); |
2863 | } else { |
2864 | result = py_return; |
2865 | } |
2866 | |
2867 | return result; |
2868 | } |
2869 | |
2870 | StructuredData::ObjectSP |
2871 | ScriptInterpreterPythonImpl::GetOptionsForCommandObject( |
2872 | StructuredData::GenericSP cmd_obj_sp) { |
2873 | StructuredData::ObjectSP result = {}; |
2874 | |
2875 | Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); |
2876 | |
2877 | static char callee_name[] = "get_options_definition" ; |
2878 | |
2879 | if (!cmd_obj_sp) |
2880 | return result; |
2881 | |
2882 | PythonObject implementor(PyRefType::Borrowed, |
2883 | (PyObject *)cmd_obj_sp->GetValue()); |
2884 | |
2885 | if (!implementor.IsAllocated()) |
2886 | return result; |
2887 | |
2888 | PythonObject pmeth(PyRefType::Owned, |
2889 | PyObject_GetAttrString(implementor.get(), callee_name)); |
2890 | |
2891 | if (PyErr_Occurred()) |
2892 | PyErr_Clear(); |
2893 | |
2894 | if (!pmeth.IsAllocated()) |
2895 | return result; |
2896 | |
2897 | if (PyCallable_Check(pmeth.get()) == 0) { |
2898 | if (PyErr_Occurred()) |
2899 | PyErr_Clear(); |
2900 | return result; |
2901 | } |
2902 | |
2903 | if (PyErr_Occurred()) |
2904 | PyErr_Clear(); |
2905 | |
2906 | PythonDictionary py_return = unwrapOrSetPythonException( |
2907 | expected: As<PythonDictionary>(obj: implementor.CallMethod(name: callee_name))); |
2908 | |
2909 | // if it fails, print the error but otherwise go on |
2910 | if (PyErr_Occurred()) { |
2911 | PyErr_Print(); |
2912 | PyErr_Clear(); |
2913 | return {}; |
2914 | } |
2915 | return py_return.CreateStructuredObject(); |
2916 | } |
2917 | |
2918 | StructuredData::ObjectSP |
2919 | ScriptInterpreterPythonImpl::GetArgumentsForCommandObject( |
2920 | StructuredData::GenericSP cmd_obj_sp) { |
2921 | StructuredData::ObjectSP result = {}; |
2922 | |
2923 | Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); |
2924 | |
2925 | static char callee_name[] = "get_args_definition" ; |
2926 | |
2927 | if (!cmd_obj_sp) |
2928 | return result; |
2929 | |
2930 | PythonObject implementor(PyRefType::Borrowed, |
2931 | (PyObject *)cmd_obj_sp->GetValue()); |
2932 | |
2933 | if (!implementor.IsAllocated()) |
2934 | return result; |
2935 | |
2936 | PythonObject pmeth(PyRefType::Owned, |
2937 | PyObject_GetAttrString(implementor.get(), callee_name)); |
2938 | |
2939 | if (PyErr_Occurred()) |
2940 | PyErr_Clear(); |
2941 | |
2942 | if (!pmeth.IsAllocated()) |
2943 | return result; |
2944 | |
2945 | if (PyCallable_Check(pmeth.get()) == 0) { |
2946 | if (PyErr_Occurred()) |
2947 | PyErr_Clear(); |
2948 | return result; |
2949 | } |
2950 | |
2951 | if (PyErr_Occurred()) |
2952 | PyErr_Clear(); |
2953 | |
2954 | PythonList py_return = unwrapOrSetPythonException( |
2955 | expected: As<PythonList>(obj: implementor.CallMethod(name: callee_name))); |
2956 | |
2957 | // if it fails, print the error but otherwise go on |
2958 | if (PyErr_Occurred()) { |
2959 | PyErr_Print(); |
2960 | PyErr_Clear(); |
2961 | return {}; |
2962 | } |
2963 | return py_return.CreateStructuredObject(); |
2964 | } |
2965 | |
2966 | void ScriptInterpreterPythonImpl::OptionParsingStartedForCommandObject( |
2967 | StructuredData::GenericSP cmd_obj_sp) { |
2968 | |
2969 | Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); |
2970 | |
2971 | static char callee_name[] = "option_parsing_started" ; |
2972 | |
2973 | if (!cmd_obj_sp) |
2974 | return; |
2975 | |
2976 | PythonObject implementor(PyRefType::Borrowed, |
2977 | (PyObject *)cmd_obj_sp->GetValue()); |
2978 | |
2979 | if (!implementor.IsAllocated()) |
2980 | return; |
2981 | |
2982 | PythonObject pmeth(PyRefType::Owned, |
2983 | PyObject_GetAttrString(implementor.get(), callee_name)); |
2984 | |
2985 | if (PyErr_Occurred()) |
2986 | PyErr_Clear(); |
2987 | |
2988 | if (!pmeth.IsAllocated()) |
2989 | return; |
2990 | |
2991 | if (PyCallable_Check(pmeth.get()) == 0) { |
2992 | if (PyErr_Occurred()) |
2993 | PyErr_Clear(); |
2994 | return; |
2995 | } |
2996 | |
2997 | if (PyErr_Occurred()) |
2998 | PyErr_Clear(); |
2999 | |
3000 | // option_parsing_starting doesn't return anything, ignore anything but |
3001 | // python errors. |
3002 | unwrapOrSetPythonException(expected: As<bool>(obj: implementor.CallMethod(name: callee_name))); |
3003 | |
3004 | // if it fails, print the error but otherwise go on |
3005 | if (PyErr_Occurred()) { |
3006 | PyErr_Print(); |
3007 | PyErr_Clear(); |
3008 | return; |
3009 | } |
3010 | } |
3011 | |
3012 | bool ScriptInterpreterPythonImpl::SetOptionValueForCommandObject( |
3013 | StructuredData::GenericSP cmd_obj_sp, ExecutionContext *exe_ctx, |
3014 | llvm::StringRef long_option, llvm::StringRef value) { |
3015 | StructuredData::ObjectSP result = {}; |
3016 | |
3017 | Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); |
3018 | |
3019 | static char callee_name[] = "set_option_value" ; |
3020 | |
3021 | if (!cmd_obj_sp) |
3022 | return false; |
3023 | |
3024 | PythonObject implementor(PyRefType::Borrowed, |
3025 | (PyObject *)cmd_obj_sp->GetValue()); |
3026 | |
3027 | if (!implementor.IsAllocated()) |
3028 | return false; |
3029 | |
3030 | PythonObject pmeth(PyRefType::Owned, |
3031 | PyObject_GetAttrString(implementor.get(), callee_name)); |
3032 | |
3033 | if (PyErr_Occurred()) |
3034 | PyErr_Clear(); |
3035 | |
3036 | if (!pmeth.IsAllocated()) |
3037 | return false; |
3038 | |
3039 | if (PyCallable_Check(pmeth.get()) == 0) { |
3040 | if (PyErr_Occurred()) |
3041 | PyErr_Clear(); |
3042 | return false; |
3043 | } |
3044 | |
3045 | if (PyErr_Occurred()) |
3046 | PyErr_Clear(); |
3047 | |
3048 | lldb::ExecutionContextRefSP exe_ctx_ref_sp; |
3049 | if (exe_ctx) |
3050 | exe_ctx_ref_sp.reset(p: new ExecutionContextRef(exe_ctx)); |
3051 | PythonObject ctx_ref_obj = SWIGBridge::ToSWIGWrapper(ctx_sp: exe_ctx_ref_sp); |
3052 | |
3053 | bool py_return = unwrapOrSetPythonException(expected: As<bool>( |
3054 | obj: implementor.CallMethod(name: callee_name, t: ctx_ref_obj, |
3055 | t: long_option.str().c_str(), t: value.str().c_str()))); |
3056 | |
3057 | // if it fails, print the error but otherwise go on |
3058 | if (PyErr_Occurred()) { |
3059 | PyErr_Print(); |
3060 | PyErr_Clear(); |
3061 | return false; |
3062 | } |
3063 | return py_return; |
3064 | } |
3065 | |
3066 | bool ScriptInterpreterPythonImpl::GetLongHelpForCommandObject( |
3067 | StructuredData::GenericSP cmd_obj_sp, std::string &dest) { |
3068 | dest.clear(); |
3069 | |
3070 | Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); |
3071 | |
3072 | if (!cmd_obj_sp) |
3073 | return false; |
3074 | |
3075 | PythonObject implementor(PyRefType::Borrowed, |
3076 | (PyObject *)cmd_obj_sp->GetValue()); |
3077 | |
3078 | if (!implementor.IsAllocated()) |
3079 | return false; |
3080 | |
3081 | llvm::Expected<PythonObject> expected_py_return = |
3082 | implementor.CallMethod(name: "get_long_help" ); |
3083 | |
3084 | if (!expected_py_return) { |
3085 | llvm::consumeError(Err: expected_py_return.takeError()); |
3086 | return false; |
3087 | } |
3088 | |
3089 | PythonObject py_return = std::move(expected_py_return.get()); |
3090 | |
3091 | bool got_string = false; |
3092 | if (py_return.IsAllocated() && PythonString::Check(py_obj: py_return.get())) { |
3093 | PythonString str(PyRefType::Borrowed, py_return.get()); |
3094 | llvm::StringRef str_data(str.GetString()); |
3095 | dest.assign(s: str_data.data(), n: str_data.size()); |
3096 | got_string = true; |
3097 | } |
3098 | |
3099 | return got_string; |
3100 | } |
3101 | |
3102 | std::unique_ptr<ScriptInterpreterLocker> |
3103 | ScriptInterpreterPythonImpl::AcquireInterpreterLock() { |
3104 | std::unique_ptr<ScriptInterpreterLocker> py_lock(new Locker( |
3105 | this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN, |
3106 | Locker::FreeLock | Locker::TearDownSession)); |
3107 | return py_lock; |
3108 | } |
3109 | |
3110 | void ScriptInterpreterPythonImpl::Initialize() { |
3111 | LLDB_SCOPED_TIMER(); |
3112 | |
3113 | // RAII-based initialization which correctly handles multiple-initialization, |
3114 | // version- specific differences among Python 2 and Python 3, and saving and |
3115 | // restoring various other pieces of state that can get mucked with during |
3116 | // initialization. |
3117 | InitializePythonRAII initialize_guard; |
3118 | |
3119 | LLDBSwigPyInit(); |
3120 | |
3121 | // Update the path python uses to search for modules to include the current |
3122 | // directory. |
3123 | |
3124 | PyRun_SimpleString("import sys" ); |
3125 | AddToSysPath(location: AddLocation::End, path: "." ); |
3126 | |
3127 | // Don't denormalize paths when calling file_spec.GetPath(). On platforms |
3128 | // that use a backslash as the path separator, this will result in executing |
3129 | // python code containing paths with unescaped backslashes. But Python also |
3130 | // accepts forward slashes, so to make life easier we just use that. |
3131 | if (FileSpec file_spec = GetPythonDir()) |
3132 | AddToSysPath(location: AddLocation::Beginning, path: file_spec.GetPath(denormalize: false)); |
3133 | if (FileSpec file_spec = HostInfo::GetShlibDir()) |
3134 | AddToSysPath(location: AddLocation::Beginning, path: file_spec.GetPath(denormalize: false)); |
3135 | |
3136 | PyRun_SimpleString("sys.dont_write_bytecode = 1; import " |
3137 | "lldb.embedded_interpreter; from " |
3138 | "lldb.embedded_interpreter import run_python_interpreter; " |
3139 | "from lldb.embedded_interpreter import run_one_line" ); |
3140 | |
3141 | #if LLDB_USE_PYTHON_SET_INTERRUPT |
3142 | // Python will not just overwrite its internal SIGINT handler but also the |
3143 | // one from the process. Backup the current SIGINT handler to prevent that |
3144 | // Python deletes it. |
3145 | RestoreSignalHandlerScope save_sigint(SIGINT); |
3146 | |
3147 | // Setup a default SIGINT signal handler that works the same way as the |
3148 | // normal Python REPL signal handler which raises a KeyboardInterrupt. |
3149 | // Also make sure to not pollute the user's REPL with the signal module nor |
3150 | // our utility function. |
3151 | PyRun_SimpleString("def lldb_setup_sigint_handler():\n" |
3152 | " import signal;\n" |
3153 | " def signal_handler(sig, frame):\n" |
3154 | " raise KeyboardInterrupt()\n" |
3155 | " signal.signal(signal.SIGINT, signal_handler);\n" |
3156 | "lldb_setup_sigint_handler();\n" |
3157 | "del lldb_setup_sigint_handler\n" ); |
3158 | #endif |
3159 | } |
3160 | |
3161 | void ScriptInterpreterPythonImpl::AddToSysPath(AddLocation location, |
3162 | std::string path) { |
3163 | std::string statement; |
3164 | if (location == AddLocation::Beginning) { |
3165 | statement.assign(s: "sys.path.insert(0,\"" ); |
3166 | statement.append(str: path); |
3167 | statement.append(s: "\")" ); |
3168 | } else { |
3169 | statement.assign(s: "sys.path.append(\"" ); |
3170 | statement.append(str: path); |
3171 | statement.append(s: "\")" ); |
3172 | } |
3173 | PyRun_SimpleString(statement.c_str()); |
3174 | } |
3175 | |
3176 | // We are intentionally NOT calling Py_Finalize here (this would be the logical |
3177 | // place to call it). Calling Py_Finalize here causes test suite runs to seg |
3178 | // fault: The test suite runs in Python. It registers SBDebugger::Terminate to |
3179 | // be called 'at_exit'. When the test suite Python harness finishes up, it |
3180 | // calls Py_Finalize, which calls all the 'at_exit' registered functions. |
3181 | // SBDebugger::Terminate calls Debugger::Terminate, which calls lldb::Terminate, |
3182 | // which calls ScriptInterpreter::Terminate, which calls |
3183 | // ScriptInterpreterPythonImpl::Terminate. So if we call Py_Finalize here, we |
3184 | // end up with Py_Finalize being called from within Py_Finalize, which results |
3185 | // in a seg fault. Since this function only gets called when lldb is shutting |
3186 | // down and going away anyway, the fact that we don't actually call Py_Finalize |
3187 | // should not cause any problems (everything should shut down/go away anyway |
3188 | // when the process exits). |
3189 | // |
3190 | // void ScriptInterpreterPythonImpl::Terminate() { Py_Finalize (); } |
3191 | |
3192 | #endif |
3193 | |