1 //===-- HostInfoBase.cpp ----------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Host/Config.h"
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/Log.h"
17 #include "lldb/Utility/StreamString.h"
19 #include "llvm/ADT/StringExtras.h"
20 #include "llvm/ADT/Triple.h"
21 #include "llvm/Support/Host.h"
22 #include "llvm/Support/Path.h"
23 #include "llvm/Support/ScopedPrinter.h"
24 #include "llvm/Support/Threading.h"
25 #include "llvm/Support/raw_ostream.h"
31 using namespace lldb_private;
34 // The HostInfoBaseFields is a work around for windows not supporting static
35 // variables correctly in a thread safe way. Really each of the variables in
36 // HostInfoBaseFields should live in the functions in which they are used and
37 // each one should be static, but the work around is in place to avoid this
40 struct HostInfoBaseFields {
41 ~HostInfoBaseFields() {
42 if (FileSystem::Instance().Exists(m_lldb_process_tmp_dir)) {
43 // Remove the LLDB temporary directory if we have one. Set "recurse" to
44 // true to all files that were created for the LLDB process can be
46 llvm::sys::fs::remove_directories(m_lldb_process_tmp_dir.GetPath());
50 std::string m_host_triple;
52 ArchSpec m_host_arch_32;
53 ArchSpec m_host_arch_64;
55 FileSpec m_lldb_so_dir;
56 FileSpec m_lldb_support_exe_dir;
57 FileSpec m_lldb_headers_dir;
58 FileSpec m_lldb_clang_resource_dir;
59 FileSpec m_lldb_system_plugin_dir;
60 FileSpec m_lldb_user_plugin_dir;
61 FileSpec m_lldb_process_tmp_dir;
62 FileSpec m_lldb_global_tmp_dir;
65 HostInfoBaseFields *g_fields = nullptr;
68 void HostInfoBase::Initialize() { g_fields = new HostInfoBaseFields(); }
70 void HostInfoBase::Terminate() {
75 llvm::StringRef HostInfoBase::GetTargetTriple() {
76 static llvm::once_flag g_once_flag;
77 llvm::call_once(g_once_flag, []() {
78 g_fields->m_host_triple =
79 HostInfo::GetArchitecture().GetTriple().getTriple();
81 return g_fields->m_host_triple;
84 const ArchSpec &HostInfoBase::GetArchitecture(ArchitectureKind arch_kind) {
85 static llvm::once_flag g_once_flag;
86 llvm::call_once(g_once_flag, []() {
87 HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32,
88 g_fields->m_host_arch_64);
91 // If an explicit 32 or 64-bit architecture was requested, return that.
92 if (arch_kind == eArchKind32)
93 return g_fields->m_host_arch_32;
94 if (arch_kind == eArchKind64)
95 return g_fields->m_host_arch_64;
97 // Otherwise prefer the 64-bit architecture if it is valid.
98 return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64
99 : g_fields->m_host_arch_32;
102 llvm::Optional<HostInfoBase::ArchitectureKind> HostInfoBase::ParseArchitectureKind(llvm::StringRef kind) {
103 return llvm::StringSwitch<llvm::Optional<ArchitectureKind>>(kind)
104 .Case(LLDB_ARCH_DEFAULT, eArchKindDefault)
105 .Case(LLDB_ARCH_DEFAULT_32BIT, eArchKind32)
106 .Case(LLDB_ARCH_DEFAULT_64BIT, eArchKind64)
107 .Default(llvm::None);
110 FileSpec HostInfoBase::GetShlibDir() {
111 static llvm::once_flag g_once_flag;
112 static bool success = false;
113 llvm::call_once(g_once_flag, []() {
114 success = HostInfo::ComputeSharedLibraryDirectory(g_fields->m_lldb_so_dir);
115 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
116 LLDB_LOG(log, "shlib dir -> `{0}`", g_fields->m_lldb_so_dir);
118 return success ? g_fields->m_lldb_so_dir : FileSpec();
121 FileSpec HostInfoBase::GetSupportExeDir() {
122 static llvm::once_flag g_once_flag;
123 static bool success = false;
124 llvm::call_once(g_once_flag, []() {
126 HostInfo::ComputeSupportExeDirectory(g_fields->m_lldb_support_exe_dir);
127 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
128 LLDB_LOG(log, "support exe dir -> `{0}`", g_fields->m_lldb_support_exe_dir);
130 return success ? g_fields->m_lldb_support_exe_dir : FileSpec();
133 FileSpec HostInfoBase::GetHeaderDir() {
134 static llvm::once_flag g_once_flag;
135 static bool success = false;
136 llvm::call_once(g_once_flag, []() {
137 success = HostInfo::ComputeHeaderDirectory(g_fields->m_lldb_headers_dir);
138 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
139 LLDB_LOG(log, "header dir -> `{0}`", g_fields->m_lldb_headers_dir);
141 return success ? g_fields->m_lldb_headers_dir : FileSpec();
144 FileSpec HostInfoBase::GetSystemPluginDir() {
145 static llvm::once_flag g_once_flag;
146 static bool success = false;
147 llvm::call_once(g_once_flag, []() {
148 success = HostInfo::ComputeSystemPluginsDirectory(
149 g_fields->m_lldb_system_plugin_dir);
150 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
151 LLDB_LOG(log, "system plugin dir -> `{0}`",
152 g_fields->m_lldb_system_plugin_dir);
154 return success ? g_fields->m_lldb_system_plugin_dir : FileSpec();
157 FileSpec HostInfoBase::GetUserPluginDir() {
158 static llvm::once_flag g_once_flag;
159 static bool success = false;
160 llvm::call_once(g_once_flag, []() {
162 HostInfo::ComputeUserPluginsDirectory(g_fields->m_lldb_user_plugin_dir);
163 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
164 LLDB_LOG(log, "user plugin dir -> `{0}`", g_fields->m_lldb_user_plugin_dir);
166 return success ? g_fields->m_lldb_user_plugin_dir : FileSpec();
169 FileSpec HostInfoBase::GetProcessTempDir() {
170 static llvm::once_flag g_once_flag;
171 static bool success = false;
172 llvm::call_once(g_once_flag, []() {
173 success = HostInfo::ComputeProcessTempFileDirectory(
174 g_fields->m_lldb_process_tmp_dir);
175 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
176 LLDB_LOG(log, "process temp dir -> `{0}`",
177 g_fields->m_lldb_process_tmp_dir);
179 return success ? g_fields->m_lldb_process_tmp_dir : FileSpec();
182 FileSpec HostInfoBase::GetGlobalTempDir() {
183 static llvm::once_flag g_once_flag;
184 static bool success = false;
185 llvm::call_once(g_once_flag, []() {
186 success = HostInfo::ComputeGlobalTempFileDirectory(
187 g_fields->m_lldb_global_tmp_dir);
188 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
189 LLDB_LOG(log, "global temp dir -> `{0}`", g_fields->m_lldb_global_tmp_dir);
191 return success ? g_fields->m_lldb_global_tmp_dir : FileSpec();
194 ArchSpec HostInfoBase::GetAugmentedArchSpec(llvm::StringRef triple) {
197 llvm::Triple normalized_triple(llvm::Triple::normalize(triple));
198 if (!ArchSpec::ContainsOnlyArch(normalized_triple))
199 return ArchSpec(triple);
201 if (auto kind = HostInfo::ParseArchitectureKind(triple))
202 return HostInfo::GetArchitecture(*kind);
204 llvm::Triple host_triple(llvm::sys::getDefaultTargetTriple());
206 if (normalized_triple.getVendorName().empty())
207 normalized_triple.setVendor(host_triple.getVendor());
208 if (normalized_triple.getOSName().empty())
209 normalized_triple.setOS(host_triple.getOS());
210 if (normalized_triple.getEnvironmentName().empty())
211 normalized_triple.setEnvironment(host_triple.getEnvironment());
212 return ArchSpec(normalized_triple);
215 bool HostInfoBase::ComputePathRelativeToLibrary(FileSpec &file_spec,
216 llvm::StringRef dir) {
217 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
219 FileSpec lldb_file_spec = GetShlibDir();
223 std::string raw_path = lldb_file_spec.GetPath();
225 log->Printf("HostInfo::%s() attempting to "
226 "derive the path %s relative to liblldb install path: %s",
227 __FUNCTION__, dir.data(), raw_path.c_str());
229 // Drop bin (windows) or lib
230 llvm::StringRef parent_path = llvm::sys::path::parent_path(raw_path);
231 if (parent_path.empty()) {
233 log->Printf("HostInfo::%s() failed to find liblldb within the shared "
239 raw_path = (parent_path + dir).str();
241 log->Printf("HostInfo::%s() derived the path as: %s", __FUNCTION__,
243 file_spec.GetDirectory().SetString(raw_path);
244 return (bool)file_spec.GetDirectory();
247 bool HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec) {
248 // To get paths related to LLDB we get the path to the executable that
249 // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB".
250 // On other posix systems, we will get .../lib(64|32)?/liblldb.so.
252 FileSpec lldb_file_spec(Host::GetModuleFileSpecForHostAddress(
253 reinterpret_cast<void *>(reinterpret_cast<intptr_t>(
254 HostInfoBase::ComputeSharedLibraryDirectory))));
256 // This is necessary because when running the testsuite the shlib might be a
257 // symbolic link inside the Python resource dir.
258 FileSystem::Instance().ResolveSymbolicLink(lldb_file_spec, lldb_file_spec);
260 // Remove the filename so that this FileSpec only represents the directory.
261 file_spec.GetDirectory() = lldb_file_spec.GetDirectory();
263 return (bool)file_spec.GetDirectory();
266 bool HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) {
267 file_spec = GetShlibDir();
268 return bool(file_spec);
271 bool HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec) {
272 FileSpec temp_file_spec;
273 if (!HostInfo::ComputeGlobalTempFileDirectory(temp_file_spec))
276 std::string pid_str{llvm::to_string(Host::GetCurrentProcessID())};
277 temp_file_spec.AppendPathComponent(pid_str);
278 if (llvm::sys::fs::create_directory(temp_file_spec.GetPath()))
281 file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
285 bool HostInfoBase::ComputeTempFileBaseDirectory(FileSpec &file_spec) {
286 llvm::SmallVector<char, 16> tmpdir;
287 llvm::sys::path::system_temp_directory(/*ErasedOnReboot*/ true, tmpdir);
288 file_spec = FileSpec(std::string(tmpdir.data(), tmpdir.size()));
289 FileSystem::Instance().Resolve(file_spec);
293 bool HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) {
296 FileSpec temp_file_spec;
297 if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec))
300 temp_file_spec.AppendPathComponent("lldb");
301 if (llvm::sys::fs::create_directory(temp_file_spec.GetPath()))
304 file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
308 bool HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec) {
309 // TODO(zturner): Figure out how to compute the header directory for all
314 bool HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec) {
315 // TODO(zturner): Figure out how to compute the system plugins directory for
320 bool HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) {
321 // TODO(zturner): Figure out how to compute the user plugins directory for
326 void HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32,
328 llvm::Triple triple(llvm::sys::getProcessTriple());
333 switch (triple.getArch()) {
335 arch_32.SetTriple(triple);
338 case llvm::Triple::aarch64:
339 case llvm::Triple::ppc64:
340 case llvm::Triple::ppc64le:
341 case llvm::Triple::x86_64:
342 arch_64.SetTriple(triple);
343 arch_32.SetTriple(triple.get32BitArchVariant());
346 case llvm::Triple::mips64:
347 case llvm::Triple::mips64el:
348 case llvm::Triple::sparcv9:
349 case llvm::Triple::systemz:
350 arch_64.SetTriple(triple);