1 //===-- HostInfoBase.cpp ----------------------------------------*- C++ -*-===//
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/Log.h"
17 #include "lldb/Utility/StreamString.h"
18 
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"
26 
27 #include <mutex>
28 #include <thread>
29 
30 using namespace lldb;
31 using namespace lldb_private;
32 
33 namespace {
34 //----------------------------------------------------------------------
35 // The HostInfoBaseFields is a work around for windows not supporting static
36 // variables correctly in a thread safe way. Really each of the variables in
37 // HostInfoBaseFields should live in the functions in which they are used and
38 // each one should be static, but the work around is in place to avoid this
39 // restriction. Ick.
40 //----------------------------------------------------------------------
41 
42 struct HostInfoBaseFields {
43   ~HostInfoBaseFields() {
44     if (FileSystem::Instance().Exists(m_lldb_process_tmp_dir)) {
45       // Remove the LLDB temporary directory if we have one. Set "recurse" to
46       // true to all files that were created for the LLDB process can be
47       // cleaned up.
48       llvm::sys::fs::remove_directories(m_lldb_process_tmp_dir.GetPath());
49     }
50   }
51 
52   std::string m_host_triple;
53 
54   ArchSpec m_host_arch_32;
55   ArchSpec m_host_arch_64;
56 
57   FileSpec m_lldb_so_dir;
58   FileSpec m_lldb_support_exe_dir;
59   FileSpec m_lldb_headers_dir;
60   FileSpec m_lldb_clang_resource_dir;
61   FileSpec m_lldb_system_plugin_dir;
62   FileSpec m_lldb_user_plugin_dir;
63   FileSpec m_lldb_process_tmp_dir;
64   FileSpec m_lldb_global_tmp_dir;
65 };
66 
67 HostInfoBaseFields *g_fields = nullptr;
68 }
69 
70 void HostInfoBase::Initialize() { g_fields = new HostInfoBaseFields(); }
71 
72 void HostInfoBase::Terminate() {
73   delete g_fields;
74   g_fields = nullptr;
75 }
76 
77 llvm::StringRef HostInfoBase::GetTargetTriple() {
78   static llvm::once_flag g_once_flag;
79   llvm::call_once(g_once_flag, []() {
80     g_fields->m_host_triple =
81         HostInfo::GetArchitecture().GetTriple().getTriple();
82   });
83   return g_fields->m_host_triple;
84 }
85 
86 const ArchSpec &HostInfoBase::GetArchitecture(ArchitectureKind arch_kind) {
87   static llvm::once_flag g_once_flag;
88   llvm::call_once(g_once_flag, []() {
89     HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32,
90                                              g_fields->m_host_arch_64);
91   });
92 
93   // If an explicit 32 or 64-bit architecture was requested, return that.
94   if (arch_kind == eArchKind32)
95     return g_fields->m_host_arch_32;
96   if (arch_kind == eArchKind64)
97     return g_fields->m_host_arch_64;
98 
99   // Otherwise prefer the 64-bit architecture if it is valid.
100   return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64
101                                               : g_fields->m_host_arch_32;
102 }
103 
104 llvm::Optional<HostInfoBase::ArchitectureKind> HostInfoBase::ParseArchitectureKind(llvm::StringRef kind) {
105   return llvm::StringSwitch<llvm::Optional<ArchitectureKind>>(kind)
106       .Case(LLDB_ARCH_DEFAULT, eArchKindDefault)
107       .Case(LLDB_ARCH_DEFAULT_32BIT, eArchKind32)
108       .Case(LLDB_ARCH_DEFAULT_64BIT, eArchKind64)
109       .Default(llvm::None);
110 }
111 
112 FileSpec HostInfoBase::GetShlibDir() {
113   static llvm::once_flag g_once_flag;
114   static bool success = false;
115   llvm::call_once(g_once_flag, []() {
116     success = HostInfo::ComputeSharedLibraryDirectory(g_fields->m_lldb_so_dir);
117     Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
118     LLDB_LOG(log, "shlib dir -> `{0}`", g_fields->m_lldb_so_dir);
119   });
120   return success ? g_fields->m_lldb_so_dir : FileSpec();
121 }
122 
123 FileSpec HostInfoBase::GetSupportExeDir() {
124   static llvm::once_flag g_once_flag;
125   static bool success = false;
126   llvm::call_once(g_once_flag, []() {
127     success =
128         HostInfo::ComputeSupportExeDirectory(g_fields->m_lldb_support_exe_dir);
129     Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
130     LLDB_LOG(log, "support exe dir -> `{0}`", g_fields->m_lldb_support_exe_dir);
131   });
132   return success ? g_fields->m_lldb_support_exe_dir : FileSpec();
133 }
134 
135 FileSpec HostInfoBase::GetHeaderDir() {
136   static llvm::once_flag g_once_flag;
137   static bool success = false;
138   llvm::call_once(g_once_flag, []() {
139     success = HostInfo::ComputeHeaderDirectory(g_fields->m_lldb_headers_dir);
140     Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
141     LLDB_LOG(log, "header dir -> `{0}`", g_fields->m_lldb_headers_dir);
142   });
143   return success ? g_fields->m_lldb_headers_dir : FileSpec();
144 }
145 
146 FileSpec HostInfoBase::GetSystemPluginDir() {
147   static llvm::once_flag g_once_flag;
148   static bool success = false;
149   llvm::call_once(g_once_flag, []() {
150     success = HostInfo::ComputeSystemPluginsDirectory(
151         g_fields->m_lldb_system_plugin_dir);
152     Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
153     LLDB_LOG(log, "system plugin dir -> `{0}`",
154              g_fields->m_lldb_system_plugin_dir);
155   });
156   return success ? g_fields->m_lldb_system_plugin_dir : FileSpec();
157 }
158 
159 FileSpec HostInfoBase::GetUserPluginDir() {
160   static llvm::once_flag g_once_flag;
161   static bool success = false;
162   llvm::call_once(g_once_flag, []() {
163     success =
164         HostInfo::ComputeUserPluginsDirectory(g_fields->m_lldb_user_plugin_dir);
165     Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
166     LLDB_LOG(log, "user plugin dir -> `{0}`", g_fields->m_lldb_user_plugin_dir);
167   });
168   return success ? g_fields->m_lldb_user_plugin_dir : FileSpec();
169 }
170 
171 FileSpec HostInfoBase::GetProcessTempDir() {
172   static llvm::once_flag g_once_flag;
173   static bool success = false;
174   llvm::call_once(g_once_flag, []() {
175     success = HostInfo::ComputeProcessTempFileDirectory(
176         g_fields->m_lldb_process_tmp_dir);
177     Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
178     LLDB_LOG(log, "process temp dir -> `{0}`",
179              g_fields->m_lldb_process_tmp_dir);
180   });
181   return success ? g_fields->m_lldb_process_tmp_dir : FileSpec();
182 }
183 
184 FileSpec HostInfoBase::GetGlobalTempDir() {
185   static llvm::once_flag g_once_flag;
186   static bool success = false;
187   llvm::call_once(g_once_flag, []() {
188     success = HostInfo::ComputeGlobalTempFileDirectory(
189         g_fields->m_lldb_global_tmp_dir);
190     Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
191     LLDB_LOG(log, "global temp dir -> `{0}`", g_fields->m_lldb_global_tmp_dir);
192   });
193   return success ? g_fields->m_lldb_global_tmp_dir : FileSpec();
194 }
195 
196 ArchSpec HostInfoBase::GetAugmentedArchSpec(llvm::StringRef triple) {
197   if (triple.empty())
198     return ArchSpec();
199   llvm::Triple normalized_triple(llvm::Triple::normalize(triple));
200   if (!ArchSpec::ContainsOnlyArch(normalized_triple))
201     return ArchSpec(triple);
202 
203   if (auto kind = HostInfo::ParseArchitectureKind(triple))
204     return HostInfo::GetArchitecture(*kind);
205 
206   llvm::Triple host_triple(llvm::sys::getDefaultTargetTriple());
207 
208   if (normalized_triple.getVendorName().empty())
209     normalized_triple.setVendor(host_triple.getVendor());
210   if (normalized_triple.getOSName().empty())
211     normalized_triple.setOS(host_triple.getOS());
212   if (normalized_triple.getEnvironmentName().empty())
213     normalized_triple.setEnvironment(host_triple.getEnvironment());
214   return ArchSpec(normalized_triple);
215 }
216 
217 bool HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec) {
218   // To get paths related to LLDB we get the path to the executable that
219   // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB".
220   // On other posix systems, we will get .../lib(64|32)?/liblldb.so.
221 
222   FileSpec lldb_file_spec(Host::GetModuleFileSpecForHostAddress(
223       reinterpret_cast<void *>(reinterpret_cast<intptr_t>(
224           HostInfoBase::ComputeSharedLibraryDirectory))));
225 
226   // This is necessary because when running the testsuite the shlib might be a
227   // symbolic link inside the Python resource dir.
228   FileSystem::Instance().ResolveSymbolicLink(lldb_file_spec, lldb_file_spec);
229 
230   // Remove the filename so that this FileSpec only represents the directory.
231   file_spec.GetDirectory() = lldb_file_spec.GetDirectory();
232 
233   return (bool)file_spec.GetDirectory();
234 }
235 
236 bool HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) {
237   file_spec = GetShlibDir();
238   return bool(file_spec);
239 }
240 
241 bool HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec) {
242   FileSpec temp_file_spec;
243   if (!HostInfo::ComputeGlobalTempFileDirectory(temp_file_spec))
244     return false;
245 
246   std::string pid_str{llvm::to_string(Host::GetCurrentProcessID())};
247   temp_file_spec.AppendPathComponent(pid_str);
248   if (llvm::sys::fs::create_directory(temp_file_spec.GetPath()))
249     return false;
250 
251   file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
252   return true;
253 }
254 
255 bool HostInfoBase::ComputeTempFileBaseDirectory(FileSpec &file_spec) {
256   llvm::SmallVector<char, 16> tmpdir;
257   llvm::sys::path::system_temp_directory(/*ErasedOnReboot*/ true, tmpdir);
258   file_spec = FileSpec(std::string(tmpdir.data(), tmpdir.size()));
259   FileSystem::Instance().Resolve(file_spec);
260   return true;
261 }
262 
263 bool HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) {
264   file_spec.Clear();
265 
266   FileSpec temp_file_spec;
267   if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec))
268     return false;
269 
270   temp_file_spec.AppendPathComponent("lldb");
271   if (llvm::sys::fs::create_directory(temp_file_spec.GetPath()))
272     return false;
273 
274   file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
275   return true;
276 }
277 
278 bool HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec) {
279   // TODO(zturner): Figure out how to compute the header directory for all
280   // platforms.
281   return false;
282 }
283 
284 bool HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec) {
285   // TODO(zturner): Figure out how to compute the system plugins directory for
286   // all platforms.
287   return false;
288 }
289 
290 bool HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) {
291   // TODO(zturner): Figure out how to compute the user plugins directory for
292   // all platforms.
293   return false;
294 }
295 
296 void HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32,
297                                                   ArchSpec &arch_64) {
298   llvm::Triple triple(llvm::sys::getProcessTriple());
299 
300   arch_32.Clear();
301   arch_64.Clear();
302 
303   switch (triple.getArch()) {
304   default:
305     arch_32.SetTriple(triple);
306     break;
307 
308   case llvm::Triple::aarch64:
309   case llvm::Triple::ppc64:
310   case llvm::Triple::ppc64le:
311   case llvm::Triple::x86_64:
312     arch_64.SetTriple(triple);
313     arch_32.SetTriple(triple.get32BitArchVariant());
314     break;
315 
316   case llvm::Triple::mips64:
317   case llvm::Triple::mips64el:
318   case llvm::Triple::sparcv9:
319   case llvm::Triple::systemz:
320     arch_64.SetTriple(triple);
321     break;
322   }
323 }
324