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 | LogChannelSystem::Initialize(); |
80 | } |
81 | |
82 | void HostInfoBase::Terminate() { |
83 | LogChannelSystem::Terminate(); |
84 | g_shlib_dir_helper = nullptr; |
85 | delete g_fields; |
86 | g_fields = nullptr; |
87 | } |
88 | |
89 | llvm::Triple HostInfoBase::GetTargetTriple() { |
90 | llvm::call_once(flag&: g_fields->m_host_triple_once, F: []() { |
91 | g_fields->m_host_triple = HostInfo::GetArchitecture().GetTriple(); |
92 | }); |
93 | return g_fields->m_host_triple; |
94 | } |
95 | |
96 | const ArchSpec &HostInfoBase::GetArchitecture(ArchitectureKind arch_kind) { |
97 | llvm::call_once(flag&: g_fields->m_host_arch_once, F: []() { |
98 | HostInfo::ComputeHostArchitectureSupport(arch_32&: g_fields->m_host_arch_32, |
99 | arch_64&: g_fields->m_host_arch_64); |
100 | }); |
101 | |
102 | // If an explicit 32 or 64-bit architecture was requested, return that. |
103 | if (arch_kind == eArchKind32) |
104 | return g_fields->m_host_arch_32; |
105 | if (arch_kind == eArchKind64) |
106 | return g_fields->m_host_arch_64; |
107 | |
108 | // Otherwise prefer the 64-bit architecture if it is valid. |
109 | return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64 |
110 | : g_fields->m_host_arch_32; |
111 | } |
112 | |
113 | std::optional<HostInfoBase::ArchitectureKind> |
114 | HostInfoBase::ParseArchitectureKind(llvm::StringRef kind) { |
115 | return llvm::StringSwitch<std::optional<ArchitectureKind>>(kind) |
116 | .Case(LLDB_ARCH_DEFAULT, Value: eArchKindDefault) |
117 | .Case(LLDB_ARCH_DEFAULT_32BIT, Value: eArchKind32) |
118 | .Case(LLDB_ARCH_DEFAULT_64BIT, Value: eArchKind64) |
119 | .Default(Value: std::nullopt); |
120 | } |
121 | |
122 | FileSpec HostInfoBase::GetShlibDir() { |
123 | llvm::call_once(flag&: g_fields->m_lldb_so_dir_once, F: []() { |
124 | if (!HostInfo::ComputeSharedLibraryDirectory(file_spec&: g_fields->m_lldb_so_dir)) |
125 | g_fields->m_lldb_so_dir = FileSpec(); |
126 | Log *log = GetLog(mask: LLDBLog::Host); |
127 | LLDB_LOG(log, "shlib dir -> `{0}`" , g_fields->m_lldb_so_dir); |
128 | }); |
129 | return g_fields->m_lldb_so_dir; |
130 | } |
131 | |
132 | FileSpec HostInfoBase::GetSupportExeDir() { |
133 | llvm::call_once(flag&: g_fields->m_lldb_support_exe_dir_once, F: []() { |
134 | if (!HostInfo::ComputeSupportExeDirectory(file_spec&: g_fields->m_lldb_support_exe_dir)) |
135 | g_fields->m_lldb_support_exe_dir = FileSpec(); |
136 | Log *log = GetLog(mask: LLDBLog::Host); |
137 | LLDB_LOG(log, "support exe dir -> `{0}`" , g_fields->m_lldb_support_exe_dir); |
138 | }); |
139 | return g_fields->m_lldb_support_exe_dir; |
140 | } |
141 | |
142 | FileSpec HostInfoBase::() { |
143 | llvm::call_once(flag&: g_fields->m_lldb_headers_dir_once, F: []() { |
144 | if (!HostInfo::ComputeHeaderDirectory(file_spec&: g_fields->m_lldb_headers_dir)) |
145 | g_fields->m_lldb_headers_dir = FileSpec(); |
146 | Log *log = GetLog(mask: LLDBLog::Host); |
147 | LLDB_LOG(log, "header dir -> `{0}`" , g_fields->m_lldb_headers_dir); |
148 | }); |
149 | return g_fields->m_lldb_headers_dir; |
150 | } |
151 | |
152 | FileSpec HostInfoBase::GetSystemPluginDir() { |
153 | llvm::call_once(flag&: g_fields->m_lldb_system_plugin_dir_once, F: []() { |
154 | if (!HostInfo::ComputeSystemPluginsDirectory( |
155 | file_spec&: g_fields->m_lldb_system_plugin_dir)) |
156 | g_fields->m_lldb_system_plugin_dir = FileSpec(); |
157 | Log *log = GetLog(mask: LLDBLog::Host); |
158 | LLDB_LOG(log, "system plugin dir -> `{0}`" , |
159 | g_fields->m_lldb_system_plugin_dir); |
160 | }); |
161 | return g_fields->m_lldb_system_plugin_dir; |
162 | } |
163 | |
164 | FileSpec HostInfoBase::GetUserPluginDir() { |
165 | llvm::call_once(flag&: g_fields->m_lldb_user_plugin_dir_once, F: []() { |
166 | if (!HostInfo::ComputeUserPluginsDirectory( |
167 | file_spec&: g_fields->m_lldb_user_plugin_dir)) |
168 | g_fields->m_lldb_user_plugin_dir = FileSpec(); |
169 | Log *log = GetLog(mask: LLDBLog::Host); |
170 | LLDB_LOG(log, "user plugin dir -> `{0}`" , g_fields->m_lldb_user_plugin_dir); |
171 | }); |
172 | return g_fields->m_lldb_user_plugin_dir; |
173 | } |
174 | |
175 | FileSpec HostInfoBase::GetProcessTempDir() { |
176 | llvm::call_once(flag&: g_fields->m_lldb_process_tmp_dir_once, F: []() { |
177 | if (!HostInfo::ComputeProcessTempFileDirectory( |
178 | file_spec&: g_fields->m_lldb_process_tmp_dir)) |
179 | g_fields->m_lldb_process_tmp_dir = FileSpec(); |
180 | Log *log = GetLog(mask: LLDBLog::Host); |
181 | LLDB_LOG(log, "process temp dir -> `{0}`" , |
182 | g_fields->m_lldb_process_tmp_dir); |
183 | }); |
184 | return g_fields->m_lldb_process_tmp_dir; |
185 | } |
186 | |
187 | FileSpec HostInfoBase::GetGlobalTempDir() { |
188 | llvm::call_once(flag&: g_fields->m_lldb_global_tmp_dir_once, F: []() { |
189 | if (!HostInfo::ComputeGlobalTempFileDirectory( |
190 | file_spec&: g_fields->m_lldb_global_tmp_dir)) |
191 | g_fields->m_lldb_global_tmp_dir = FileSpec(); |
192 | |
193 | Log *log = GetLog(mask: LLDBLog::Host); |
194 | LLDB_LOG(log, "global temp dir -> `{0}`" , g_fields->m_lldb_global_tmp_dir); |
195 | }); |
196 | return g_fields->m_lldb_global_tmp_dir; |
197 | } |
198 | |
199 | ArchSpec HostInfoBase::GetAugmentedArchSpec(llvm::StringRef triple) { |
200 | if (triple.empty()) |
201 | return ArchSpec(); |
202 | llvm::Triple normalized_triple(llvm::Triple::normalize(Str: triple)); |
203 | if (!ArchSpec::ContainsOnlyArch(normalized_triple)) |
204 | return ArchSpec(triple); |
205 | |
206 | if (auto kind = HostInfo::ParseArchitectureKind(kind: triple)) |
207 | return HostInfo::GetArchitecture(arch_kind: *kind); |
208 | |
209 | llvm::Triple host_triple(llvm::sys::getDefaultTargetTriple()); |
210 | |
211 | if (normalized_triple.getVendorName().empty()) |
212 | normalized_triple.setVendor(host_triple.getVendor()); |
213 | if (normalized_triple.getOSName().empty()) |
214 | normalized_triple.setOS(host_triple.getOS()); |
215 | if (normalized_triple.getEnvironmentName().empty() && |
216 | !host_triple.getEnvironmentName().empty()) |
217 | normalized_triple.setEnvironment(host_triple.getEnvironment()); |
218 | return ArchSpec(normalized_triple); |
219 | } |
220 | |
221 | bool HostInfoBase::ComputePathRelativeToLibrary(FileSpec &file_spec, |
222 | llvm::StringRef dir) { |
223 | Log *log = GetLog(mask: LLDBLog::Host); |
224 | |
225 | FileSpec lldb_file_spec = GetShlibDir(); |
226 | if (!lldb_file_spec) |
227 | return false; |
228 | |
229 | std::string raw_path = lldb_file_spec.GetPath(); |
230 | LLDB_LOG( |
231 | log, |
232 | "Attempting to derive the path {0} relative to liblldb install path: {1}" , |
233 | dir, raw_path); |
234 | |
235 | // Drop bin (windows) or lib |
236 | llvm::StringRef parent_path = llvm::sys::path::parent_path(path: raw_path); |
237 | if (parent_path.empty()) { |
238 | LLDB_LOG(log, "Failed to find liblldb within the shared lib path" ); |
239 | return false; |
240 | } |
241 | |
242 | raw_path = (parent_path + dir).str(); |
243 | LLDB_LOG(log, "Derived the path as: {0}" , raw_path); |
244 | file_spec.SetDirectory(raw_path); |
245 | return (bool)file_spec.GetDirectory(); |
246 | } |
247 | |
248 | bool HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec) { |
249 | // To get paths related to LLDB we get the path to the executable that |
250 | // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB". |
251 | // On other posix systems, we will get .../lib(64|32)?/liblldb.so. |
252 | |
253 | FileSpec lldb_file_spec(Host::GetModuleFileSpecForHostAddress( |
254 | host_addr: reinterpret_cast<void *>(HostInfoBase::ComputeSharedLibraryDirectory))); |
255 | |
256 | if (g_shlib_dir_helper) |
257 | g_shlib_dir_helper(lldb_file_spec); |
258 | |
259 | // Remove the filename so that this FileSpec only represents the directory. |
260 | file_spec.SetDirectory(lldb_file_spec.GetDirectory()); |
261 | |
262 | return (bool)file_spec.GetDirectory(); |
263 | } |
264 | |
265 | bool HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) { |
266 | file_spec = GetShlibDir(); |
267 | return bool(file_spec); |
268 | } |
269 | |
270 | bool HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec) { |
271 | FileSpec temp_file_spec; |
272 | if (!HostInfo::ComputeGlobalTempFileDirectory(file_spec&: temp_file_spec)) |
273 | return false; |
274 | |
275 | std::string pid_str{llvm::to_string(Value: Host::GetCurrentProcessID())}; |
276 | temp_file_spec.AppendPathComponent(component: pid_str); |
277 | if (llvm::sys::fs::create_directory(path: temp_file_spec.GetPath())) |
278 | return false; |
279 | |
280 | file_spec.SetDirectory(temp_file_spec.GetPathAsConstString()); |
281 | return true; |
282 | } |
283 | |
284 | bool HostInfoBase::ComputeTempFileBaseDirectory(FileSpec &file_spec) { |
285 | llvm::SmallVector<char, 16> tmpdir; |
286 | llvm::sys::path::system_temp_directory(/*ErasedOnReboot*/ erasedOnReboot: true, result&: tmpdir); |
287 | file_spec = FileSpec(std::string(tmpdir.data(), tmpdir.size())); |
288 | FileSystem::Instance().Resolve(file_spec); |
289 | return true; |
290 | } |
291 | |
292 | bool HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) { |
293 | file_spec.Clear(); |
294 | |
295 | FileSpec temp_file_spec; |
296 | if (!HostInfo::ComputeTempFileBaseDirectory(file_spec&: temp_file_spec)) |
297 | return false; |
298 | |
299 | temp_file_spec.AppendPathComponent(component: "lldb" ); |
300 | if (llvm::sys::fs::create_directory(path: temp_file_spec.GetPath())) |
301 | return false; |
302 | |
303 | file_spec.SetDirectory(temp_file_spec.GetPathAsConstString()); |
304 | return true; |
305 | } |
306 | |
307 | bool HostInfoBase::(FileSpec &file_spec) { |
308 | // TODO(zturner): Figure out how to compute the header directory for all |
309 | // platforms. |
310 | return false; |
311 | } |
312 | |
313 | bool HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec) { |
314 | // TODO(zturner): Figure out how to compute the system plugins directory for |
315 | // all platforms. |
316 | return false; |
317 | } |
318 | |
319 | bool HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) { |
320 | // TODO(zturner): Figure out how to compute the user plugins directory for |
321 | // all platforms. |
322 | return false; |
323 | } |
324 | |
325 | void HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, |
326 | ArchSpec &arch_64) { |
327 | llvm::Triple triple(llvm::sys::getProcessTriple()); |
328 | |
329 | arch_32.Clear(); |
330 | arch_64.Clear(); |
331 | |
332 | switch (triple.getArch()) { |
333 | default: |
334 | arch_32.SetTriple(triple); |
335 | break; |
336 | |
337 | case llvm::Triple::aarch64: |
338 | case llvm::Triple::ppc64: |
339 | case llvm::Triple::ppc64le: |
340 | case llvm::Triple::x86_64: |
341 | case llvm::Triple::riscv64: |
342 | case llvm::Triple::loongarch64: |
343 | arch_64.SetTriple(triple); |
344 | arch_32.SetTriple(triple.get32BitArchVariant()); |
345 | break; |
346 | |
347 | case llvm::Triple::mips64: |
348 | case llvm::Triple::mips64el: |
349 | case llvm::Triple::sparcv9: |
350 | case llvm::Triple::systemz: |
351 | arch_64.SetTriple(triple); |
352 | break; |
353 | } |
354 | } |
355 | |