1dda28197Spatrick //===-- HostInfoBase.cpp --------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "lldb/Host/Config.h"
10061da546Spatrick
11061da546Spatrick #include "lldb/Host/FileSystem.h"
12061da546Spatrick #include "lldb/Host/Host.h"
13061da546Spatrick #include "lldb/Host/HostInfo.h"
14061da546Spatrick #include "lldb/Host/HostInfoBase.h"
15061da546Spatrick #include "lldb/Utility/ArchSpec.h"
16*f6aab3d8Srobert #include "lldb/Utility/LLDBLog.h"
17061da546Spatrick #include "lldb/Utility/Log.h"
18061da546Spatrick #include "lldb/Utility/StreamString.h"
19061da546Spatrick
20061da546Spatrick #include "llvm/ADT/StringExtras.h"
21061da546Spatrick #include "llvm/ADT/Triple.h"
22061da546Spatrick #include "llvm/Support/Host.h"
23061da546Spatrick #include "llvm/Support/Path.h"
24061da546Spatrick #include "llvm/Support/ScopedPrinter.h"
25061da546Spatrick #include "llvm/Support/Threading.h"
26061da546Spatrick #include "llvm/Support/raw_ostream.h"
27061da546Spatrick
28061da546Spatrick #include <mutex>
29*f6aab3d8Srobert #include <optional>
30061da546Spatrick #include <thread>
31061da546Spatrick
32061da546Spatrick using namespace lldb;
33061da546Spatrick using namespace lldb_private;
34061da546Spatrick
35061da546Spatrick namespace {
36be691f3bSpatrick /// Contains the state of the HostInfoBase plugin.
37061da546Spatrick struct HostInfoBaseFields {
~HostInfoBaseFields__anon3ed34a4e0111::HostInfoBaseFields38061da546Spatrick ~HostInfoBaseFields() {
39061da546Spatrick if (FileSystem::Instance().Exists(m_lldb_process_tmp_dir)) {
40061da546Spatrick // Remove the LLDB temporary directory if we have one. Set "recurse" to
41061da546Spatrick // true to all files that were created for the LLDB process can be
42061da546Spatrick // cleaned up.
43061da546Spatrick llvm::sys::fs::remove_directories(m_lldb_process_tmp_dir.GetPath());
44061da546Spatrick }
45061da546Spatrick }
46061da546Spatrick
47061da546Spatrick llvm::once_flag m_host_triple_once;
48061da546Spatrick llvm::Triple m_host_triple;
49061da546Spatrick
50061da546Spatrick llvm::once_flag m_host_arch_once;
51061da546Spatrick ArchSpec m_host_arch_32;
52061da546Spatrick ArchSpec m_host_arch_64;
53061da546Spatrick
54061da546Spatrick llvm::once_flag m_lldb_so_dir_once;
55061da546Spatrick FileSpec m_lldb_so_dir;
56061da546Spatrick llvm::once_flag m_lldb_support_exe_dir_once;
57061da546Spatrick FileSpec m_lldb_support_exe_dir;
58061da546Spatrick llvm::once_flag m_lldb_headers_dir_once;
59061da546Spatrick FileSpec m_lldb_headers_dir;
60061da546Spatrick llvm::once_flag m_lldb_clang_resource_dir_once;
61061da546Spatrick FileSpec m_lldb_clang_resource_dir;
62061da546Spatrick llvm::once_flag m_lldb_system_plugin_dir_once;
63061da546Spatrick FileSpec m_lldb_system_plugin_dir;
64061da546Spatrick llvm::once_flag m_lldb_user_plugin_dir_once;
65061da546Spatrick FileSpec m_lldb_user_plugin_dir;
66061da546Spatrick llvm::once_flag m_lldb_process_tmp_dir_once;
67061da546Spatrick FileSpec m_lldb_process_tmp_dir;
68061da546Spatrick llvm::once_flag m_lldb_global_tmp_dir_once;
69061da546Spatrick FileSpec m_lldb_global_tmp_dir;
70061da546Spatrick };
71be691f3bSpatrick } // namespace
72061da546Spatrick
73be691f3bSpatrick static HostInfoBaseFields *g_fields = nullptr;
74be691f3bSpatrick static HostInfoBase::SharedLibraryDirectoryHelper *g_shlib_dir_helper = nullptr;
75be691f3bSpatrick
Initialize(SharedLibraryDirectoryHelper * helper)76be691f3bSpatrick void HostInfoBase::Initialize(SharedLibraryDirectoryHelper *helper) {
77be691f3bSpatrick g_shlib_dir_helper = helper;
78be691f3bSpatrick g_fields = new HostInfoBaseFields();
79061da546Spatrick }
80061da546Spatrick
Terminate()81061da546Spatrick void HostInfoBase::Terminate() {
82be691f3bSpatrick g_shlib_dir_helper = nullptr;
83061da546Spatrick delete g_fields;
84061da546Spatrick g_fields = nullptr;
85061da546Spatrick }
86061da546Spatrick
GetTargetTriple()87061da546Spatrick llvm::Triple HostInfoBase::GetTargetTriple() {
88061da546Spatrick llvm::call_once(g_fields->m_host_triple_once, []() {
89*f6aab3d8Srobert g_fields->m_host_triple = HostInfo::GetArchitecture().GetTriple();
90061da546Spatrick });
91061da546Spatrick return g_fields->m_host_triple;
92061da546Spatrick }
93061da546Spatrick
GetArchitecture(ArchitectureKind arch_kind)94061da546Spatrick const ArchSpec &HostInfoBase::GetArchitecture(ArchitectureKind arch_kind) {
95061da546Spatrick llvm::call_once(g_fields->m_host_arch_once, []() {
96061da546Spatrick HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32,
97061da546Spatrick g_fields->m_host_arch_64);
98061da546Spatrick });
99061da546Spatrick
100061da546Spatrick // If an explicit 32 or 64-bit architecture was requested, return that.
101061da546Spatrick if (arch_kind == eArchKind32)
102061da546Spatrick return g_fields->m_host_arch_32;
103061da546Spatrick if (arch_kind == eArchKind64)
104061da546Spatrick return g_fields->m_host_arch_64;
105061da546Spatrick
106061da546Spatrick // Otherwise prefer the 64-bit architecture if it is valid.
107061da546Spatrick return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64
108061da546Spatrick : g_fields->m_host_arch_32;
109061da546Spatrick }
110061da546Spatrick
111*f6aab3d8Srobert std::optional<HostInfoBase::ArchitectureKind>
ParseArchitectureKind(llvm::StringRef kind)112*f6aab3d8Srobert HostInfoBase::ParseArchitectureKind(llvm::StringRef kind) {
113*f6aab3d8Srobert return llvm::StringSwitch<std::optional<ArchitectureKind>>(kind)
114061da546Spatrick .Case(LLDB_ARCH_DEFAULT, eArchKindDefault)
115061da546Spatrick .Case(LLDB_ARCH_DEFAULT_32BIT, eArchKind32)
116061da546Spatrick .Case(LLDB_ARCH_DEFAULT_64BIT, eArchKind64)
117*f6aab3d8Srobert .Default(std::nullopt);
118061da546Spatrick }
119061da546Spatrick
GetShlibDir()120061da546Spatrick FileSpec HostInfoBase::GetShlibDir() {
121061da546Spatrick llvm::call_once(g_fields->m_lldb_so_dir_once, []() {
122061da546Spatrick if (!HostInfo::ComputeSharedLibraryDirectory(g_fields->m_lldb_so_dir))
123061da546Spatrick g_fields->m_lldb_so_dir = FileSpec();
124*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Host);
125061da546Spatrick LLDB_LOG(log, "shlib dir -> `{0}`", g_fields->m_lldb_so_dir);
126061da546Spatrick });
127061da546Spatrick return g_fields->m_lldb_so_dir;
128061da546Spatrick }
129061da546Spatrick
GetSupportExeDir()130061da546Spatrick FileSpec HostInfoBase::GetSupportExeDir() {
131061da546Spatrick llvm::call_once(g_fields->m_lldb_support_exe_dir_once, []() {
132061da546Spatrick if (!HostInfo::ComputeSupportExeDirectory(g_fields->m_lldb_support_exe_dir))
133061da546Spatrick g_fields->m_lldb_support_exe_dir = FileSpec();
134*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Host);
135061da546Spatrick LLDB_LOG(log, "support exe dir -> `{0}`", g_fields->m_lldb_support_exe_dir);
136061da546Spatrick });
137061da546Spatrick return g_fields->m_lldb_support_exe_dir;
138061da546Spatrick }
139061da546Spatrick
GetHeaderDir()140061da546Spatrick FileSpec HostInfoBase::GetHeaderDir() {
141061da546Spatrick llvm::call_once(g_fields->m_lldb_headers_dir_once, []() {
142061da546Spatrick if (!HostInfo::ComputeHeaderDirectory(g_fields->m_lldb_headers_dir))
143061da546Spatrick g_fields->m_lldb_headers_dir = FileSpec();
144*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Host);
145061da546Spatrick LLDB_LOG(log, "header dir -> `{0}`", g_fields->m_lldb_headers_dir);
146061da546Spatrick });
147061da546Spatrick return g_fields->m_lldb_headers_dir;
148061da546Spatrick }
149061da546Spatrick
GetSystemPluginDir()150061da546Spatrick FileSpec HostInfoBase::GetSystemPluginDir() {
151061da546Spatrick llvm::call_once(g_fields->m_lldb_system_plugin_dir_once, []() {
152*f6aab3d8Srobert if (!HostInfo::ComputeSystemPluginsDirectory(
153*f6aab3d8Srobert g_fields->m_lldb_system_plugin_dir))
154061da546Spatrick g_fields->m_lldb_system_plugin_dir = FileSpec();
155*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Host);
156061da546Spatrick LLDB_LOG(log, "system plugin dir -> `{0}`",
157061da546Spatrick g_fields->m_lldb_system_plugin_dir);
158061da546Spatrick });
159061da546Spatrick return g_fields->m_lldb_system_plugin_dir;
160061da546Spatrick }
161061da546Spatrick
GetUserPluginDir()162061da546Spatrick FileSpec HostInfoBase::GetUserPluginDir() {
163061da546Spatrick llvm::call_once(g_fields->m_lldb_user_plugin_dir_once, []() {
164*f6aab3d8Srobert if (!HostInfo::ComputeUserPluginsDirectory(
165*f6aab3d8Srobert g_fields->m_lldb_user_plugin_dir))
166061da546Spatrick g_fields->m_lldb_user_plugin_dir = FileSpec();
167*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Host);
168061da546Spatrick LLDB_LOG(log, "user plugin dir -> `{0}`", g_fields->m_lldb_user_plugin_dir);
169061da546Spatrick });
170061da546Spatrick return g_fields->m_lldb_user_plugin_dir;
171061da546Spatrick }
172061da546Spatrick
GetProcessTempDir()173061da546Spatrick FileSpec HostInfoBase::GetProcessTempDir() {
174061da546Spatrick llvm::call_once(g_fields->m_lldb_process_tmp_dir_once, []() {
175*f6aab3d8Srobert if (!HostInfo::ComputeProcessTempFileDirectory(
176*f6aab3d8Srobert g_fields->m_lldb_process_tmp_dir))
177061da546Spatrick g_fields->m_lldb_process_tmp_dir = FileSpec();
178*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Host);
179061da546Spatrick LLDB_LOG(log, "process temp dir -> `{0}`",
180061da546Spatrick g_fields->m_lldb_process_tmp_dir);
181061da546Spatrick });
182061da546Spatrick return g_fields->m_lldb_process_tmp_dir;
183061da546Spatrick }
184061da546Spatrick
GetGlobalTempDir()185061da546Spatrick FileSpec HostInfoBase::GetGlobalTempDir() {
186061da546Spatrick llvm::call_once(g_fields->m_lldb_global_tmp_dir_once, []() {
187*f6aab3d8Srobert if (!HostInfo::ComputeGlobalTempFileDirectory(
188*f6aab3d8Srobert g_fields->m_lldb_global_tmp_dir))
189061da546Spatrick g_fields->m_lldb_global_tmp_dir = FileSpec();
190061da546Spatrick
191*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Host);
192061da546Spatrick LLDB_LOG(log, "global temp dir -> `{0}`", g_fields->m_lldb_global_tmp_dir);
193061da546Spatrick });
194061da546Spatrick return g_fields->m_lldb_global_tmp_dir;
195061da546Spatrick }
196061da546Spatrick
GetAugmentedArchSpec(llvm::StringRef triple)197061da546Spatrick ArchSpec HostInfoBase::GetAugmentedArchSpec(llvm::StringRef triple) {
198061da546Spatrick if (triple.empty())
199061da546Spatrick return ArchSpec();
200061da546Spatrick llvm::Triple normalized_triple(llvm::Triple::normalize(triple));
201061da546Spatrick if (!ArchSpec::ContainsOnlyArch(normalized_triple))
202061da546Spatrick return ArchSpec(triple);
203061da546Spatrick
204061da546Spatrick if (auto kind = HostInfo::ParseArchitectureKind(triple))
205061da546Spatrick return HostInfo::GetArchitecture(*kind);
206061da546Spatrick
207061da546Spatrick llvm::Triple host_triple(llvm::sys::getDefaultTargetTriple());
208061da546Spatrick
209061da546Spatrick if (normalized_triple.getVendorName().empty())
210061da546Spatrick normalized_triple.setVendor(host_triple.getVendor());
211061da546Spatrick if (normalized_triple.getOSName().empty())
212061da546Spatrick normalized_triple.setOS(host_triple.getOS());
213*f6aab3d8Srobert if (normalized_triple.getEnvironmentName().empty() &&
214*f6aab3d8Srobert !host_triple.getEnvironmentName().empty())
215061da546Spatrick normalized_triple.setEnvironment(host_triple.getEnvironment());
216061da546Spatrick return ArchSpec(normalized_triple);
217061da546Spatrick }
218061da546Spatrick
ComputePathRelativeToLibrary(FileSpec & file_spec,llvm::StringRef dir)219061da546Spatrick bool HostInfoBase::ComputePathRelativeToLibrary(FileSpec &file_spec,
220061da546Spatrick llvm::StringRef dir) {
221*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Host);
222061da546Spatrick
223061da546Spatrick FileSpec lldb_file_spec = GetShlibDir();
224061da546Spatrick if (!lldb_file_spec)
225061da546Spatrick return false;
226061da546Spatrick
227061da546Spatrick std::string raw_path = lldb_file_spec.GetPath();
228061da546Spatrick LLDB_LOGF(log,
229061da546Spatrick "HostInfo::%s() attempting to "
230061da546Spatrick "derive the path %s relative to liblldb install path: %s",
231061da546Spatrick __FUNCTION__, dir.data(), raw_path.c_str());
232061da546Spatrick
233061da546Spatrick // Drop bin (windows) or lib
234061da546Spatrick llvm::StringRef parent_path = llvm::sys::path::parent_path(raw_path);
235061da546Spatrick if (parent_path.empty()) {
236061da546Spatrick LLDB_LOGF(log,
237061da546Spatrick "HostInfo::%s() failed to find liblldb within the shared "
238061da546Spatrick "lib path",
239061da546Spatrick __FUNCTION__);
240061da546Spatrick return false;
241061da546Spatrick }
242061da546Spatrick
243061da546Spatrick raw_path = (parent_path + dir).str();
244061da546Spatrick LLDB_LOGF(log, "HostInfo::%s() derived the path as: %s", __FUNCTION__,
245061da546Spatrick raw_path.c_str());
246*f6aab3d8Srobert file_spec.SetDirectory(raw_path);
247061da546Spatrick return (bool)file_spec.GetDirectory();
248061da546Spatrick }
249061da546Spatrick
ComputeSharedLibraryDirectory(FileSpec & file_spec)250061da546Spatrick bool HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec) {
251061da546Spatrick // To get paths related to LLDB we get the path to the executable that
252061da546Spatrick // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB".
253061da546Spatrick // On other posix systems, we will get .../lib(64|32)?/liblldb.so.
254061da546Spatrick
255061da546Spatrick FileSpec lldb_file_spec(Host::GetModuleFileSpecForHostAddress(
256*f6aab3d8Srobert reinterpret_cast<void *>(HostInfoBase::ComputeSharedLibraryDirectory)));
257061da546Spatrick
258be691f3bSpatrick if (g_shlib_dir_helper)
259be691f3bSpatrick g_shlib_dir_helper(lldb_file_spec);
260061da546Spatrick
261061da546Spatrick // Remove the filename so that this FileSpec only represents the directory.
262*f6aab3d8Srobert file_spec.SetDirectory(lldb_file_spec.GetDirectory());
263061da546Spatrick
264061da546Spatrick return (bool)file_spec.GetDirectory();
265061da546Spatrick }
266061da546Spatrick
ComputeSupportExeDirectory(FileSpec & file_spec)267061da546Spatrick bool HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) {
268061da546Spatrick file_spec = GetShlibDir();
269061da546Spatrick return bool(file_spec);
270061da546Spatrick }
271061da546Spatrick
ComputeProcessTempFileDirectory(FileSpec & file_spec)272061da546Spatrick bool HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec) {
273061da546Spatrick FileSpec temp_file_spec;
274061da546Spatrick if (!HostInfo::ComputeGlobalTempFileDirectory(temp_file_spec))
275061da546Spatrick return false;
276061da546Spatrick
277061da546Spatrick std::string pid_str{llvm::to_string(Host::GetCurrentProcessID())};
278061da546Spatrick temp_file_spec.AppendPathComponent(pid_str);
279061da546Spatrick if (llvm::sys::fs::create_directory(temp_file_spec.GetPath()))
280061da546Spatrick return false;
281061da546Spatrick
282*f6aab3d8Srobert file_spec.SetDirectory(temp_file_spec.GetPathAsConstString());
283061da546Spatrick return true;
284061da546Spatrick }
285061da546Spatrick
ComputeTempFileBaseDirectory(FileSpec & file_spec)286061da546Spatrick bool HostInfoBase::ComputeTempFileBaseDirectory(FileSpec &file_spec) {
287061da546Spatrick llvm::SmallVector<char, 16> tmpdir;
288061da546Spatrick llvm::sys::path::system_temp_directory(/*ErasedOnReboot*/ true, tmpdir);
289061da546Spatrick file_spec = FileSpec(std::string(tmpdir.data(), tmpdir.size()));
290061da546Spatrick FileSystem::Instance().Resolve(file_spec);
291061da546Spatrick return true;
292061da546Spatrick }
293061da546Spatrick
ComputeGlobalTempFileDirectory(FileSpec & file_spec)294061da546Spatrick bool HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) {
295061da546Spatrick file_spec.Clear();
296061da546Spatrick
297061da546Spatrick FileSpec temp_file_spec;
298061da546Spatrick if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec))
299061da546Spatrick return false;
300061da546Spatrick
301061da546Spatrick temp_file_spec.AppendPathComponent("lldb");
302061da546Spatrick if (llvm::sys::fs::create_directory(temp_file_spec.GetPath()))
303061da546Spatrick return false;
304061da546Spatrick
305*f6aab3d8Srobert file_spec.SetDirectory(temp_file_spec.GetPathAsConstString());
306061da546Spatrick return true;
307061da546Spatrick }
308061da546Spatrick
ComputeHeaderDirectory(FileSpec & file_spec)309061da546Spatrick bool HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec) {
310061da546Spatrick // TODO(zturner): Figure out how to compute the header directory for all
311061da546Spatrick // platforms.
312061da546Spatrick return false;
313061da546Spatrick }
314061da546Spatrick
ComputeSystemPluginsDirectory(FileSpec & file_spec)315061da546Spatrick bool HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec) {
316061da546Spatrick // TODO(zturner): Figure out how to compute the system plugins directory for
317061da546Spatrick // all platforms.
318061da546Spatrick return false;
319061da546Spatrick }
320061da546Spatrick
ComputeUserPluginsDirectory(FileSpec & file_spec)321061da546Spatrick bool HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) {
322061da546Spatrick // TODO(zturner): Figure out how to compute the user plugins directory for
323061da546Spatrick // all platforms.
324061da546Spatrick return false;
325061da546Spatrick }
326061da546Spatrick
ComputeHostArchitectureSupport(ArchSpec & arch_32,ArchSpec & arch_64)327061da546Spatrick void HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32,
328061da546Spatrick ArchSpec &arch_64) {
329061da546Spatrick llvm::Triple triple(llvm::sys::getProcessTriple());
330061da546Spatrick
331061da546Spatrick arch_32.Clear();
332061da546Spatrick arch_64.Clear();
333061da546Spatrick
334061da546Spatrick switch (triple.getArch()) {
335061da546Spatrick default:
336061da546Spatrick arch_32.SetTriple(triple);
337061da546Spatrick break;
338061da546Spatrick
339061da546Spatrick case llvm::Triple::aarch64:
340061da546Spatrick case llvm::Triple::ppc64:
341061da546Spatrick case llvm::Triple::ppc64le:
342061da546Spatrick case llvm::Triple::x86_64:
343*f6aab3d8Srobert case llvm::Triple::riscv64:
344*f6aab3d8Srobert case llvm::Triple::loongarch64:
345061da546Spatrick arch_64.SetTriple(triple);
346061da546Spatrick arch_32.SetTriple(triple.get32BitArchVariant());
347061da546Spatrick break;
348061da546Spatrick
349061da546Spatrick case llvm::Triple::mips64:
350061da546Spatrick case llvm::Triple::mips64el:
351061da546Spatrick case llvm::Triple::sparcv9:
352061da546Spatrick case llvm::Triple::systemz:
353061da546Spatrick arch_64.SetTriple(triple);
354061da546Spatrick break;
355061da546Spatrick }
356061da546Spatrick }
357