1 | //===-- HostInfoBase.cpp --------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "lldb/Host/Config.h" |
10 | |
11 | #include "lldb/Host/FileSystem.h" |
12 | #include "lldb/Host/Host.h" |
13 | #include "lldb/Host/HostInfo.h" |
14 | #include "lldb/Host/HostInfoBase.h" |
15 | #include "lldb/Utility/ArchSpec.h" |
16 | #include "lldb/Utility/LLDBLog.h" |
17 | #include "lldb/Utility/Log.h" |
18 | #include "lldb/Utility/StreamString.h" |
19 | |
20 | #include "llvm/ADT/StringExtras.h" |
21 | #include "llvm/Support/Path.h" |
22 | #include "llvm/Support/ScopedPrinter.h" |
23 | #include "llvm/Support/Threading.h" |
24 | #include "llvm/Support/raw_ostream.h" |
25 | #include "llvm/TargetParser/Host.h" |
26 | #include "llvm/TargetParser/Triple.h" |
27 | |
28 | #include <mutex> |
29 | #include <optional> |
30 | #include <thread> |
31 | |
32 | using namespace lldb; |
33 | using namespace lldb_private; |
34 | |
35 | namespace { |
36 | /// Contains the state of the HostInfoBase plugin. |
37 | struct HostInfoBaseFields { |
38 | ~HostInfoBaseFields() { |
39 | if (FileSystem::Instance().Exists(file_spec: m_lldb_process_tmp_dir)) { |
40 | // Remove the LLDB temporary directory if we have one. Set "recurse" to |
41 | // true to all files that were created for the LLDB process can be |
42 | // cleaned up. |
43 | llvm::sys::fs::remove_directories(path: m_lldb_process_tmp_dir.GetPath()); |
44 | } |
45 | } |
46 | |
47 | llvm::once_flag m_host_triple_once; |
48 | llvm::Triple m_host_triple; |
49 | |
50 | llvm::once_flag m_host_arch_once; |
51 | ArchSpec m_host_arch_32; |
52 | ArchSpec m_host_arch_64; |
53 | |
54 | llvm::once_flag m_lldb_so_dir_once; |
55 | FileSpec m_lldb_so_dir; |
56 | llvm::once_flag m_lldb_support_exe_dir_once; |
57 | FileSpec m_lldb_support_exe_dir; |
58 | llvm::once_flag ; |
59 | FileSpec ; |
60 | llvm::once_flag m_lldb_clang_resource_dir_once; |
61 | FileSpec m_lldb_clang_resource_dir; |
62 | llvm::once_flag m_lldb_system_plugin_dir_once; |
63 | FileSpec m_lldb_system_plugin_dir; |
64 | llvm::once_flag m_lldb_user_plugin_dir_once; |
65 | FileSpec m_lldb_user_plugin_dir; |
66 | llvm::once_flag m_lldb_process_tmp_dir_once; |
67 | FileSpec m_lldb_process_tmp_dir; |
68 | llvm::once_flag m_lldb_global_tmp_dir_once; |
69 | FileSpec m_lldb_global_tmp_dir; |
70 | }; |
71 | } // namespace |
72 | |
73 | static HostInfoBaseFields *g_fields = nullptr; |
74 | static HostInfoBase::SharedLibraryDirectoryHelper *g_shlib_dir_helper = nullptr; |
75 | |
76 | void HostInfoBase::Initialize(SharedLibraryDirectoryHelper *helper) { |
77 | g_shlib_dir_helper = helper; |
78 | g_fields = new HostInfoBaseFields(); |
79 | } |
80 | |
81 | void HostInfoBase::Terminate() { |
82 | g_shlib_dir_helper = nullptr; |
83 | delete g_fields; |
84 | g_fields = nullptr; |
85 | } |
86 | |
87 | llvm::Triple HostInfoBase::GetTargetTriple() { |
88 | llvm::call_once(flag&: g_fields->m_host_triple_once, F: []() { |
89 | g_fields->m_host_triple = HostInfo::GetArchitecture().GetTriple(); |
90 | }); |
91 | return g_fields->m_host_triple; |
92 | } |
93 | |
94 | const ArchSpec &HostInfoBase::GetArchitecture(ArchitectureKind arch_kind) { |
95 | llvm::call_once(flag&: g_fields->m_host_arch_once, F: []() { |
96 | HostInfo::ComputeHostArchitectureSupport(arch_32&: g_fields->m_host_arch_32, |
97 | arch_64&: g_fields->m_host_arch_64); |
98 | }); |
99 | |
100 | // If an explicit 32 or 64-bit architecture was requested, return that. |
101 | if (arch_kind == eArchKind32) |
102 | return g_fields->m_host_arch_32; |
103 | if (arch_kind == eArchKind64) |
104 | return g_fields->m_host_arch_64; |
105 | |
106 | // Otherwise prefer the 64-bit architecture if it is valid. |
107 | return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64 |
108 | : g_fields->m_host_arch_32; |
109 | } |
110 | |
111 | std::optional<HostInfoBase::ArchitectureKind> |
112 | HostInfoBase::ParseArchitectureKind(llvm::StringRef kind) { |
113 | return llvm::StringSwitch<std::optional<ArchitectureKind>>(kind) |
114 | .Case(LLDB_ARCH_DEFAULT, Value: eArchKindDefault) |
115 | .Case(LLDB_ARCH_DEFAULT_32BIT, Value: eArchKind32) |
116 | .Case(LLDB_ARCH_DEFAULT_64BIT, Value: eArchKind64) |
117 | .Default(Value: std::nullopt); |
118 | } |
119 | |
120 | FileSpec HostInfoBase::GetShlibDir() { |
121 | llvm::call_once(flag&: g_fields->m_lldb_so_dir_once, F: []() { |
122 | if (!HostInfo::ComputeSharedLibraryDirectory(file_spec&: g_fields->m_lldb_so_dir)) |
123 | g_fields->m_lldb_so_dir = FileSpec(); |
124 | Log *log = GetLog(mask: LLDBLog::Host); |
125 | LLDB_LOG(log, "shlib dir -> `{0}`" , g_fields->m_lldb_so_dir); |
126 | }); |
127 | return g_fields->m_lldb_so_dir; |
128 | } |
129 | |
130 | FileSpec HostInfoBase::GetSupportExeDir() { |
131 | llvm::call_once(flag&: g_fields->m_lldb_support_exe_dir_once, F: []() { |
132 | if (!HostInfo::ComputeSupportExeDirectory(file_spec&: g_fields->m_lldb_support_exe_dir)) |
133 | g_fields->m_lldb_support_exe_dir = FileSpec(); |
134 | Log *log = GetLog(mask: LLDBLog::Host); |
135 | LLDB_LOG(log, "support exe dir -> `{0}`" , g_fields->m_lldb_support_exe_dir); |
136 | }); |
137 | return g_fields->m_lldb_support_exe_dir; |
138 | } |
139 | |
140 | FileSpec HostInfoBase::() { |
141 | llvm::call_once(flag&: g_fields->m_lldb_headers_dir_once, F: []() { |
142 | if (!HostInfo::ComputeHeaderDirectory(file_spec&: g_fields->m_lldb_headers_dir)) |
143 | g_fields->m_lldb_headers_dir = FileSpec(); |
144 | Log *log = GetLog(mask: LLDBLog::Host); |
145 | LLDB_LOG(log, "header dir -> `{0}`" , g_fields->m_lldb_headers_dir); |
146 | }); |
147 | return g_fields->m_lldb_headers_dir; |
148 | } |
149 | |
150 | FileSpec HostInfoBase::GetSystemPluginDir() { |
151 | llvm::call_once(flag&: g_fields->m_lldb_system_plugin_dir_once, F: []() { |
152 | if (!HostInfo::ComputeSystemPluginsDirectory( |
153 | file_spec&: g_fields->m_lldb_system_plugin_dir)) |
154 | g_fields->m_lldb_system_plugin_dir = FileSpec(); |
155 | Log *log = GetLog(mask: LLDBLog::Host); |
156 | LLDB_LOG(log, "system plugin dir -> `{0}`" , |
157 | g_fields->m_lldb_system_plugin_dir); |
158 | }); |
159 | return g_fields->m_lldb_system_plugin_dir; |
160 | } |
161 | |
162 | FileSpec HostInfoBase::GetUserPluginDir() { |
163 | llvm::call_once(flag&: g_fields->m_lldb_user_plugin_dir_once, F: []() { |
164 | if (!HostInfo::ComputeUserPluginsDirectory( |
165 | file_spec&: g_fields->m_lldb_user_plugin_dir)) |
166 | g_fields->m_lldb_user_plugin_dir = FileSpec(); |
167 | Log *log = GetLog(mask: LLDBLog::Host); |
168 | LLDB_LOG(log, "user plugin dir -> `{0}`" , g_fields->m_lldb_user_plugin_dir); |
169 | }); |
170 | return g_fields->m_lldb_user_plugin_dir; |
171 | } |
172 | |
173 | FileSpec HostInfoBase::GetProcessTempDir() { |
174 | llvm::call_once(flag&: g_fields->m_lldb_process_tmp_dir_once, F: []() { |
175 | if (!HostInfo::ComputeProcessTempFileDirectory( |
176 | file_spec&: g_fields->m_lldb_process_tmp_dir)) |
177 | g_fields->m_lldb_process_tmp_dir = FileSpec(); |
178 | Log *log = GetLog(mask: LLDBLog::Host); |
179 | LLDB_LOG(log, "process temp dir -> `{0}`" , |
180 | g_fields->m_lldb_process_tmp_dir); |
181 | }); |
182 | return g_fields->m_lldb_process_tmp_dir; |
183 | } |
184 | |
185 | FileSpec HostInfoBase::GetGlobalTempDir() { |
186 | llvm::call_once(flag&: g_fields->m_lldb_global_tmp_dir_once, F: []() { |
187 | if (!HostInfo::ComputeGlobalTempFileDirectory( |
188 | file_spec&: g_fields->m_lldb_global_tmp_dir)) |
189 | g_fields->m_lldb_global_tmp_dir = FileSpec(); |
190 | |
191 | Log *log = GetLog(mask: LLDBLog::Host); |
192 | LLDB_LOG(log, "global temp dir -> `{0}`" , g_fields->m_lldb_global_tmp_dir); |
193 | }); |
194 | return g_fields->m_lldb_global_tmp_dir; |
195 | } |
196 | |
197 | ArchSpec HostInfoBase::GetAugmentedArchSpec(llvm::StringRef triple) { |
198 | if (triple.empty()) |
199 | return ArchSpec(); |
200 | llvm::Triple normalized_triple(llvm::Triple::normalize(Str: triple)); |
201 | if (!ArchSpec::ContainsOnlyArch(normalized_triple)) |
202 | return ArchSpec(triple); |
203 | |
204 | if (auto kind = HostInfo::ParseArchitectureKind(kind: triple)) |
205 | return HostInfo::GetArchitecture(arch_kind: *kind); |
206 | |
207 | llvm::Triple host_triple(llvm::sys::getDefaultTargetTriple()); |
208 | |
209 | if (normalized_triple.getVendorName().empty()) |
210 | normalized_triple.setVendor(host_triple.getVendor()); |
211 | if (normalized_triple.getOSName().empty()) |
212 | normalized_triple.setOS(host_triple.getOS()); |
213 | if (normalized_triple.getEnvironmentName().empty() && |
214 | !host_triple.getEnvironmentName().empty()) |
215 | normalized_triple.setEnvironment(host_triple.getEnvironment()); |
216 | return ArchSpec(normalized_triple); |
217 | } |
218 | |
219 | bool HostInfoBase::ComputePathRelativeToLibrary(FileSpec &file_spec, |
220 | llvm::StringRef dir) { |
221 | Log *log = GetLog(mask: LLDBLog::Host); |
222 | |
223 | FileSpec lldb_file_spec = GetShlibDir(); |
224 | if (!lldb_file_spec) |
225 | return false; |
226 | |
227 | std::string raw_path = lldb_file_spec.GetPath(); |
228 | LLDB_LOG( |
229 | log, |
230 | "Attempting to derive the path {0} relative to liblldb install path: {1}" , |
231 | dir, raw_path); |
232 | |
233 | // Drop bin (windows) or lib |
234 | llvm::StringRef parent_path = llvm::sys::path::parent_path(path: raw_path); |
235 | if (parent_path.empty()) { |
236 | LLDB_LOG(log, "Failed to find liblldb within the shared lib path" ); |
237 | return false; |
238 | } |
239 | |
240 | raw_path = (parent_path + dir).str(); |
241 | LLDB_LOG(log, "Derived the path as: {0}" , raw_path); |
242 | file_spec.SetDirectory(raw_path); |
243 | return (bool)file_spec.GetDirectory(); |
244 | } |
245 | |
246 | bool HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec) { |
247 | // To get paths related to LLDB we get the path to the executable that |
248 | // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB". |
249 | // On other posix systems, we will get .../lib(64|32)?/liblldb.so. |
250 | |
251 | FileSpec lldb_file_spec(Host::GetModuleFileSpecForHostAddress( |
252 | host_addr: reinterpret_cast<void *>(HostInfoBase::ComputeSharedLibraryDirectory))); |
253 | |
254 | if (g_shlib_dir_helper) |
255 | g_shlib_dir_helper(lldb_file_spec); |
256 | |
257 | // Remove the filename so that this FileSpec only represents the directory. |
258 | file_spec.SetDirectory(lldb_file_spec.GetDirectory()); |
259 | |
260 | return (bool)file_spec.GetDirectory(); |
261 | } |
262 | |
263 | bool HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) { |
264 | file_spec = GetShlibDir(); |
265 | return bool(file_spec); |
266 | } |
267 | |
268 | bool HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec) { |
269 | FileSpec temp_file_spec; |
270 | if (!HostInfo::ComputeGlobalTempFileDirectory(file_spec&: temp_file_spec)) |
271 | return false; |
272 | |
273 | std::string pid_str{llvm::to_string(Value: Host::GetCurrentProcessID())}; |
274 | temp_file_spec.AppendPathComponent(component: pid_str); |
275 | if (llvm::sys::fs::create_directory(path: temp_file_spec.GetPath())) |
276 | return false; |
277 | |
278 | file_spec.SetDirectory(temp_file_spec.GetPathAsConstString()); |
279 | return true; |
280 | } |
281 | |
282 | bool HostInfoBase::ComputeTempFileBaseDirectory(FileSpec &file_spec) { |
283 | llvm::SmallVector<char, 16> tmpdir; |
284 | llvm::sys::path::system_temp_directory(/*ErasedOnReboot*/ erasedOnReboot: true, result&: tmpdir); |
285 | file_spec = FileSpec(std::string(tmpdir.data(), tmpdir.size())); |
286 | FileSystem::Instance().Resolve(file_spec); |
287 | return true; |
288 | } |
289 | |
290 | bool HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) { |
291 | file_spec.Clear(); |
292 | |
293 | FileSpec temp_file_spec; |
294 | if (!HostInfo::ComputeTempFileBaseDirectory(file_spec&: temp_file_spec)) |
295 | return false; |
296 | |
297 | temp_file_spec.AppendPathComponent(component: "lldb" ); |
298 | if (llvm::sys::fs::create_directory(path: temp_file_spec.GetPath())) |
299 | return false; |
300 | |
301 | file_spec.SetDirectory(temp_file_spec.GetPathAsConstString()); |
302 | return true; |
303 | } |
304 | |
305 | bool HostInfoBase::(FileSpec &file_spec) { |
306 | // TODO(zturner): Figure out how to compute the header directory for all |
307 | // platforms. |
308 | return false; |
309 | } |
310 | |
311 | bool HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec) { |
312 | // TODO(zturner): Figure out how to compute the system plugins directory for |
313 | // all platforms. |
314 | return false; |
315 | } |
316 | |
317 | bool HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) { |
318 | // TODO(zturner): Figure out how to compute the user plugins directory for |
319 | // all platforms. |
320 | return false; |
321 | } |
322 | |
323 | void HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, |
324 | ArchSpec &arch_64) { |
325 | llvm::Triple triple(llvm::sys::getProcessTriple()); |
326 | |
327 | arch_32.Clear(); |
328 | arch_64.Clear(); |
329 | |
330 | switch (triple.getArch()) { |
331 | default: |
332 | arch_32.SetTriple(triple); |
333 | break; |
334 | |
335 | case llvm::Triple::aarch64: |
336 | case llvm::Triple::ppc64: |
337 | case llvm::Triple::ppc64le: |
338 | case llvm::Triple::x86_64: |
339 | case llvm::Triple::riscv64: |
340 | case llvm::Triple::loongarch64: |
341 | arch_64.SetTriple(triple); |
342 | arch_32.SetTriple(triple.get32BitArchVariant()); |
343 | break; |
344 | |
345 | case llvm::Triple::mips64: |
346 | case llvm::Triple::mips64el: |
347 | case llvm::Triple::sparcv9: |
348 | case llvm::Triple::systemz: |
349 | arch_64.SetTriple(triple); |
350 | break; |
351 | } |
352 | } |
353 | |