LLDB mainline
PythonRuntimeLoader.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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"
11
14#include "lldb/Utility/Log.h"
15#include "llvm/ADT/SmallString.h"
16#include "llvm/Support/DynamicLibrary.h"
17#include "llvm/Support/ErrorExtras.h"
18#include "llvm/Support/Path.h"
19#include "llvm/Support/Threading.h"
20
21#include <cstdlib>
22#include <string>
23
24#if defined(_WIN32)
27#include "llvm/Support/Windows/WindowsSupport.h"
28#else
29#include <dlfcn.h>
30#endif
31
32namespace lldb_private {
33
34namespace {
35
36#if defined(_WIN32)
37#ifndef LOAD_LIBRARY_SEARCH_DEFAULT_DIRS
38#define LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 0x00001000
39#endif
40
41using SetDefaultDllDirectoriesFn = BOOL(WINAPI *)(DWORD);
42using AddDllDirectoryFn = PVOID(WINAPI *)(PCWSTR);
43
44/// Forwarded exports resolve lazily, at an arbitrary later GetProcAddress
45/// call, so the directory can never be safely removed once added.
46void RegisterDllSearchDirectory(llvm::StringRef path) {
47 llvm::StringRef dir = llvm::sys::path::parent_path(path);
48 if (dir.empty())
49 return;
50
51 static LazyImport<AddDllDirectoryFn> add_dll_directory{L"Kernel32.dll",
52 "AddDllDirectory"};
53 if (!add_dll_directory)
54 return;
55
56 static llvm::once_flag opt_in_once;
57 llvm::call_once(opt_in_once, [] {
58 static LazyImport<SetDefaultDllDirectoriesFn> set_default_dll_directories{
59 L"Kernel32.dll", "SetDefaultDllDirectories"};
60 if (set_default_dll_directories)
61 (*set_default_dll_directories)(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
62 });
63
64 llvm::SmallVector<wchar_t, MAX_PATH> wide_dir;
65 if (llvm::sys::windows::widenPath(dir, wide_dir))
66 return;
67 (*add_dll_directory)(wide_dir.data());
68}
69#endif // _WIN32
70
71/// True if libpython is currently mapped into the process. A single-symbol
72/// probe can match an incompatible runtime that happens to export it, so
73/// pair an old symbol with one introduced in 3.8 to bound the version on
74/// both ends.
75bool IsPythonAlreadyLoaded() {
76#if defined(_WIN32)
77 HMODULE main = ::GetModuleHandleW(nullptr);
78 return ::GetProcAddress(main, "Py_IsInitialized") != nullptr &&
79 ::GetProcAddress(main, "Py_InitializeFromConfig") != nullptr;
80#else
81 return ::dlsym(RTLD_DEFAULT, "Py_IsInitialized") != nullptr &&
82 ::dlsym(RTLD_DEFAULT, "Py_InitializeFromConfig") != nullptr;
83#endif
84}
85
86llvm::Error TryLoad(const char *path) {
87#if defined(_WIN32)
88 RegisterDllSearchDirectory(path);
89#endif
90 std::string err_msg;
91 llvm::sys::DynamicLibrary lib =
92 llvm::sys::DynamicLibrary::getPermanentLibrary(path, &err_msg);
93 if (!lib.isValid())
94 return llvm::createStringErrorV("could not load '{0}': {1}", path, err_msg);
95
96 // A successful load does not imply the library is actually libpython,
97 // so reject anything that doesn't expose a stable-ABI symbol.
98 if (!lib.getAddressOfSymbol("Py_IsInitialized"))
99 return llvm::createStringErrorV(
100 "'{0}' does not export Py_IsInitialized; not a Python runtime", path);
101
102 return llvm::Error::success();
103}
104
105llvm::Expected<std::string> LoadPythonRuntime() {
106 if (IsPythonAlreadyLoaded())
107 return std::string();
108
109 llvm::Error failures =
110 llvm::createStringError("could not locate the Python runtime library");
111 std::string loaded;
112
113 auto try_path = [&](const char *path) -> bool {
114 if (llvm::Error err = TryLoad(path)) {
115 failures = llvm::joinErrors(std::move(failures), std::move(err));
116 return false;
117 }
118 loaded = path;
119 return true;
120 };
121
122 if (const char *override_path = std::getenv("LLDB_PYTHON_LIBRARY");
123 override_path && *override_path) {
124 if (try_path(override_path)) {
125 consumeError(std::move(failures));
126 return loaded;
127 }
128 }
129
130#ifdef LLDB_PYTHON_RUNTIME_LIBRARY_BUILD_PATH
131 // The build-time Python is the closest stable-ABI match for what the
132 // plugin was compiled against, so prefer it over the platform fallbacks.
133 if (try_path(LLDB_PYTHON_RUNTIME_LIBRARY_BUILD_PATH)) {
134 consumeError(std::move(failures));
135 return loaded;
136 }
137#endif
138
139 bool found = false;
141 [&](const char *candidate) { return found = try_path(candidate); });
142
143 if (found) {
144 consumeError(std::move(failures));
145 return loaded;
146 }
147 return std::move(failures);
148}
149
150class PythonRuntimeLoader : public ScriptInterpreterRuntimeLoader {
151public:
152 llvm::Error Load() override {
153 EnsureLoaded();
154 if (m_error_message.empty())
155 return llvm::Error::success();
156 return llvm::createStringError(m_error_message);
157 }
158
159 llvm::Expected<llvm::StringRef> GetLoadedPath() override {
160 EnsureLoaded();
161 if (!m_error_message.empty())
162 return llvm::createStringError(m_error_message);
163 return llvm::StringRef(m_path);
164 }
165
166 bool IsLoaded() override { return IsPythonAlreadyLoaded(); }
167
168private:
169 void EnsureLoaded() {
170 llvm::call_once(m_once, [this] {
171 if (llvm::Expected<std::string> result = LoadPythonRuntime()) {
172 m_path = std::move(*result);
173 if (m_path.empty())
174 return;
175#if defined(_WIN32)
176 // liblldb.dll may link against (lib)python3.dll (stable ABI). Ensure
177 // it is loaded from the same directory as the version-specific runtime
178 // so the delay-load resolver can find it.
179 llvm::SmallString<256> stable_abi_path(m_path);
180 llvm::sys::path::remove_filename(stable_abi_path);
181#if defined(__MINGW32__)
182 llvm::sys::path::append(stable_abi_path, "libpython3.dll");
183#else
184 llvm::sys::path::append(stable_abi_path, "python3.dll");
185#endif
186 std::string err;
187 llvm::sys::DynamicLibrary::getPermanentLibrary(stable_abi_path.c_str(),
188 &err);
189#endif
190 } else {
191 m_error_message = llvm::toString(result.takeError());
192 LLDB_LOG(GetLog(LLDBLog::Host), "Python runtime load failed: {0}",
193 m_error_message);
194 }
195 });
196 }
197
198 llvm::once_flag m_once;
199 std::string m_path;
200 std::string m_error_message;
201};
202
203} // namespace
204
205llvm::Expected<ScriptInterpreterRuntimeLoader &>
207 switch (language) {
209 static PythonRuntimeLoader instance;
210 return instance;
211 }
215 return llvm::createStringError(
216 "no runtime loader for the requested script language");
217 }
218 llvm_unreachable("unhandled ScriptLanguage");
219}
220
221} // namespace lldb_private
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition Log.h:375
Loads a script-interpreter runtime into the current process before its plugin is dlopened.
static llvm::Expected< ScriptInterpreterRuntimeLoader & > Get(lldb::ScriptLanguage language)
Returns the loader for language.
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:338
void ForEachPythonRuntimeCandidate(llvm::function_ref< bool(const char *)> callback)
Visits candidate Python runtime paths in priority order, stopping at the first call that returns true...
static std::enable_if_t< is_load< I >, bool > Load(EmulateInstructionRISCV &emulator, I inst, uint64_t(*extend)(E))
ScriptLanguage
Script interpreter types.
@ eScriptLanguageUnknown
@ eScriptLanguageNone
@ eScriptLanguagePython