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