1 //===-- HostInfoBase.cpp ----------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/Host/Config.h"
11 
12 #include "lldb/Core/ArchSpec.h"
13 #include "lldb/Core/Log.h"
14 #include "lldb/Host/FileSystem.h"
15 #include "lldb/Host/Host.h"
16 #include "lldb/Host/HostInfo.h"
17 #include "lldb/Host/HostInfoBase.h"
18 #include "lldb/Utility/StreamString.h"
19 
20 #include "llvm/ADT/StringExtras.h"
21 #include "llvm/ADT/Triple.h"
22 #include "llvm/Support/Host.h"
23 #include "llvm/Support/Path.h"
24 #include "llvm/Support/ScopedPrinter.h"
25 #include "llvm/Support/Threading.h"
26 #include "llvm/Support/raw_ostream.h"
27 
28 #include <mutex>
29 #include <thread>
30 
31 using namespace lldb;
32 using namespace lldb_private;
33 
34 namespace {
35 //----------------------------------------------------------------------
36 // The HostInfoBaseFields is a work around for windows not supporting
37 // static variables correctly in a thread safe way. Really each of the
38 // variables in HostInfoBaseFields should live in the functions in which
39 // they are used and each one should be static, but the work around is
40 // in place to avoid this restriction. Ick.
41 //----------------------------------------------------------------------
42 
43 struct HostInfoBaseFields {
44   ~HostInfoBaseFields() {
45     if (m_lldb_process_tmp_dir.Exists()) {
46       // Remove the LLDB temporary directory if we have one. Set "recurse" to
47       // true to all files that were created for the LLDB process can be cleaned
48       // up.
49       FileSystem::DeleteDirectory(m_lldb_process_tmp_dir, true);
50     }
51   }
52 
53   uint32_t m_number_cpus;
54   std::string m_vendor_string;
55   std::string m_os_string;
56   std::string m_host_triple;
57 
58   ArchSpec m_host_arch_32;
59   ArchSpec m_host_arch_64;
60 
61   FileSpec m_lldb_so_dir;
62   FileSpec m_lldb_support_exe_dir;
63   FileSpec m_lldb_headers_dir;
64   FileSpec m_lldb_python_dir;
65   FileSpec m_lldb_clang_resource_dir;
66   FileSpec m_lldb_system_plugin_dir;
67   FileSpec m_lldb_user_plugin_dir;
68   FileSpec m_lldb_process_tmp_dir;
69   FileSpec m_lldb_global_tmp_dir;
70 };
71 
72 HostInfoBaseFields *g_fields = nullptr;
73 }
74 
75 void HostInfoBase::Initialize() { g_fields = new HostInfoBaseFields(); }
76 
77 void HostInfoBase::Terminate() {
78   delete g_fields;
79   g_fields = nullptr;
80 }
81 
82 uint32_t HostInfoBase::GetNumberCPUS() {
83   static llvm::once_flag g_once_flag;
84   llvm::call_once(g_once_flag, []() {
85     g_fields->m_number_cpus = std::thread::hardware_concurrency();
86   });
87   return g_fields->m_number_cpus;
88 }
89 
90 uint32_t HostInfoBase::GetMaxThreadNameLength() { return 0; }
91 
92 llvm::StringRef HostInfoBase::GetVendorString() {
93   static llvm::once_flag g_once_flag;
94   llvm::call_once(g_once_flag, []() {
95     g_fields->m_vendor_string =
96         HostInfo::GetArchitecture().GetTriple().getVendorName().str();
97   });
98   return g_fields->m_vendor_string;
99 }
100 
101 llvm::StringRef HostInfoBase::GetOSString() {
102   static llvm::once_flag g_once_flag;
103   llvm::call_once(g_once_flag, []() {
104     g_fields->m_os_string =
105         std::move(HostInfo::GetArchitecture().GetTriple().getOSName());
106   });
107   return g_fields->m_os_string;
108 }
109 
110 llvm::StringRef HostInfoBase::GetTargetTriple() {
111   static llvm::once_flag g_once_flag;
112   llvm::call_once(g_once_flag, []() {
113     g_fields->m_host_triple =
114         HostInfo::GetArchitecture().GetTriple().getTriple();
115   });
116   return g_fields->m_host_triple;
117 }
118 
119 const ArchSpec &HostInfoBase::GetArchitecture(ArchitectureKind arch_kind) {
120   static llvm::once_flag g_once_flag;
121   llvm::call_once(g_once_flag, []() {
122     HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32,
123                                              g_fields->m_host_arch_64);
124   });
125 
126   // If an explicit 32 or 64-bit architecture was requested, return that.
127   if (arch_kind == eArchKind32)
128     return g_fields->m_host_arch_32;
129   if (arch_kind == eArchKind64)
130     return g_fields->m_host_arch_64;
131 
132   // Otherwise prefer the 64-bit architecture if it is valid.
133   return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64
134                                               : g_fields->m_host_arch_32;
135 }
136 
137 bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) {
138   file_spec.Clear();
139 
140 #if defined(LLDB_DISABLE_PYTHON)
141   if (type == lldb::ePathTypePythonDir)
142     return false;
143 #endif
144 
145   FileSpec *result = nullptr;
146   switch (type) {
147   case lldb::ePathTypeLLDBShlibDir: {
148     static llvm::once_flag g_once_flag;
149     static bool success = false;
150     llvm::call_once(g_once_flag, []() {
151       success =
152           HostInfo::ComputeSharedLibraryDirectory(g_fields->m_lldb_so_dir);
153       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
154       if (log)
155         log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'",
156                     g_fields->m_lldb_so_dir.GetPath().c_str());
157     });
158     if (success)
159       result = &g_fields->m_lldb_so_dir;
160   } break;
161   case lldb::ePathTypeSupportExecutableDir: {
162     static llvm::once_flag g_once_flag;
163     static bool success = false;
164     llvm::call_once(g_once_flag, []() {
165       success = HostInfo::ComputeSupportExeDirectory(
166           g_fields->m_lldb_support_exe_dir);
167       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
168       if (log)
169         log->Printf(
170             "HostInfoBase::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'",
171             g_fields->m_lldb_support_exe_dir.GetPath().c_str());
172     });
173     if (success)
174       result = &g_fields->m_lldb_support_exe_dir;
175   } break;
176   case lldb::ePathTypeHeaderDir: {
177     static llvm::once_flag g_once_flag;
178     static bool success = false;
179     llvm::call_once(g_once_flag, []() {
180       success = HostInfo::ComputeHeaderDirectory(g_fields->m_lldb_headers_dir);
181       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
182       if (log)
183         log->Printf("HostInfoBase::GetLLDBPath(ePathTypeHeaderDir) => '%s'",
184                     g_fields->m_lldb_headers_dir.GetPath().c_str());
185     });
186     if (success)
187       result = &g_fields->m_lldb_headers_dir;
188   } break;
189   case lldb::ePathTypePythonDir: {
190     static llvm::once_flag g_once_flag;
191     static bool success = false;
192     llvm::call_once(g_once_flag, []() {
193       success = HostInfo::ComputePythonDirectory(g_fields->m_lldb_python_dir);
194       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
195       if (log)
196         log->Printf("HostInfoBase::GetLLDBPath(ePathTypePythonDir) => '%s'",
197                     g_fields->m_lldb_python_dir.GetPath().c_str());
198     });
199     if (success)
200       result = &g_fields->m_lldb_python_dir;
201   } break;
202   case lldb::ePathTypeClangDir: {
203     static llvm::once_flag g_once_flag;
204     static bool success = false;
205     llvm::call_once(g_once_flag, []() {
206       success =
207           HostInfo::ComputeClangDirectory(g_fields->m_lldb_clang_resource_dir);
208       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
209       if (log)
210         log->Printf(
211             "HostInfoBase::GetLLDBPath(ePathTypeClangResourceDir) => '%s'",
212             g_fields->m_lldb_clang_resource_dir.GetPath().c_str());
213     });
214     if (success)
215       result = &g_fields->m_lldb_clang_resource_dir;
216   } break;
217   case lldb::ePathTypeLLDBSystemPlugins: {
218     static llvm::once_flag g_once_flag;
219     static bool success = false;
220     llvm::call_once(g_once_flag, []() {
221       success = HostInfo::ComputeSystemPluginsDirectory(
222           g_fields->m_lldb_system_plugin_dir);
223       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
224       if (log)
225         log->Printf(
226             "HostInfoBase::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'",
227             g_fields->m_lldb_system_plugin_dir.GetPath().c_str());
228     });
229     if (success)
230       result = &g_fields->m_lldb_system_plugin_dir;
231   } break;
232   case lldb::ePathTypeLLDBUserPlugins: {
233     static llvm::once_flag g_once_flag;
234     static bool success = false;
235     llvm::call_once(g_once_flag, []() {
236       success = HostInfo::ComputeUserPluginsDirectory(
237           g_fields->m_lldb_user_plugin_dir);
238       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
239       if (log)
240         log->Printf(
241             "HostInfoBase::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'",
242             g_fields->m_lldb_user_plugin_dir.GetPath().c_str());
243     });
244     if (success)
245       result = &g_fields->m_lldb_user_plugin_dir;
246   } break;
247   case lldb::ePathTypeLLDBTempSystemDir: {
248     static llvm::once_flag g_once_flag;
249     static bool success = false;
250     llvm::call_once(g_once_flag, []() {
251       success = HostInfo::ComputeProcessTempFileDirectory(
252           g_fields->m_lldb_process_tmp_dir);
253       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
254       if (log)
255         log->Printf(
256             "HostInfoBase::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'",
257             g_fields->m_lldb_process_tmp_dir.GetPath().c_str());
258     });
259     if (success)
260       result = &g_fields->m_lldb_process_tmp_dir;
261   } break;
262   case lldb::ePathTypeGlobalLLDBTempSystemDir: {
263     static llvm::once_flag g_once_flag;
264     static bool success = false;
265     llvm::call_once(g_once_flag, []() {
266       success = HostInfo::ComputeGlobalTempFileDirectory(
267           g_fields->m_lldb_global_tmp_dir);
268       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
269       if (log)
270         log->Printf("HostInfoBase::GetLLDBPath("
271                     "ePathTypeGlobalLLDBTempSystemDir) => '%s'",
272                     g_fields->m_lldb_global_tmp_dir.GetPath().c_str());
273     });
274     if (success)
275       result = &g_fields->m_lldb_global_tmp_dir;
276   } break;
277   }
278 
279   if (!result)
280     return false;
281   file_spec = *result;
282   return true;
283 }
284 
285 bool HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec) {
286   // To get paths related to LLDB we get the path to the executable that
287   // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB",
288   // on linux this is assumed to be the "lldb" main executable. If LLDB on
289   // linux is actually in a shared library (liblldb.so) then this function will
290   // need to be modified to "do the right thing".
291 
292   FileSpec lldb_file_spec(
293       Host::GetModuleFileSpecForHostAddress(reinterpret_cast<void *>(
294           reinterpret_cast<intptr_t>(HostInfoBase::GetLLDBPath))));
295 
296   // This is necessary because when running the testsuite the shlib might be a
297   // symbolic link inside the Python resource dir.
298   FileSystem::ResolveSymbolicLink(lldb_file_spec, lldb_file_spec);
299 
300   // Remove the filename so that this FileSpec only represents the directory.
301   file_spec.GetDirectory() = lldb_file_spec.GetDirectory();
302 
303   return (bool)file_spec.GetDirectory();
304 }
305 
306 bool HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) {
307   return GetLLDBPath(lldb::ePathTypeLLDBShlibDir, file_spec);
308 }
309 
310 bool HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec) {
311   FileSpec temp_file_spec;
312   if (!HostInfo::ComputeGlobalTempFileDirectory(temp_file_spec))
313     return false;
314 
315   std::string pid_str{llvm::to_string(Host::GetCurrentProcessID())};
316   temp_file_spec.AppendPathComponent(pid_str);
317   if (!FileSystem::MakeDirectory(temp_file_spec,
318                                  eFilePermissionsDirectoryDefault)
319            .Success())
320     return false;
321 
322   file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
323   return true;
324 }
325 
326 bool HostInfoBase::ComputeTempFileBaseDirectory(FileSpec &file_spec) {
327   llvm::SmallVector<char, 16> tmpdir;
328   llvm::sys::path::system_temp_directory(/*ErasedOnReboot*/ true, tmpdir);
329   file_spec = FileSpec(std::string(tmpdir.data(), tmpdir.size()), true);
330   return true;
331 }
332 
333 bool HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) {
334   file_spec.Clear();
335 
336   FileSpec temp_file_spec;
337   if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec))
338     return false;
339 
340   temp_file_spec.AppendPathComponent("lldb");
341   if (!FileSystem::MakeDirectory(temp_file_spec,
342                                  eFilePermissionsDirectoryDefault)
343            .Success())
344     return false;
345 
346   file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
347   return true;
348 }
349 
350 bool HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec) {
351   // TODO(zturner): Figure out how to compute the header directory for all
352   // platforms.
353   return false;
354 }
355 
356 bool HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec) {
357   // TODO(zturner): Figure out how to compute the system plugins directory for
358   // all platforms.
359   return false;
360 }
361 
362 bool HostInfoBase::ComputeClangDirectory(FileSpec &file_spec) { return false; }
363 
364 bool HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) {
365   // TODO(zturner): Figure out how to compute the user plugins directory for all
366   // platforms.
367   return false;
368 }
369 
370 void HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32,
371                                                   ArchSpec &arch_64) {
372   llvm::Triple triple(llvm::sys::getProcessTriple());
373 
374   arch_32.Clear();
375   arch_64.Clear();
376 
377   switch (triple.getArch()) {
378   default:
379     arch_32.SetTriple(triple);
380     break;
381 
382   case llvm::Triple::aarch64:
383   case llvm::Triple::ppc64:
384   case llvm::Triple::x86_64:
385     arch_64.SetTriple(triple);
386     arch_32.SetTriple(triple.get32BitArchVariant());
387     break;
388 
389   case llvm::Triple::mips64:
390   case llvm::Triple::mips64el:
391   case llvm::Triple::sparcv9:
392   case llvm::Triple::systemz:
393     arch_64.SetTriple(triple);
394     break;
395   }
396 }
397