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/Host/FileSystem.h"
13 #include "lldb/Host/Host.h"
14 #include "lldb/Host/HostInfo.h"
15 #include "lldb/Host/HostInfoBase.h"
16 #include "lldb/Utility/ArchSpec.h"
17 #include "lldb/Utility/Log.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       llvm::sys::fs::remove_directories(m_lldb_process_tmp_dir.GetPath());
50     }
51   }
52 
53   std::string m_host_triple;
54 
55   ArchSpec m_host_arch_32;
56   ArchSpec m_host_arch_64;
57 
58   FileSpec m_lldb_so_dir;
59   FileSpec m_lldb_support_exe_dir;
60   FileSpec m_lldb_headers_dir;
61   FileSpec m_lldb_python_dir;
62   FileSpec m_lldb_clang_resource_dir;
63   FileSpec m_lldb_system_plugin_dir;
64   FileSpec m_lldb_user_plugin_dir;
65   FileSpec m_lldb_process_tmp_dir;
66   FileSpec m_lldb_global_tmp_dir;
67 };
68 
69 HostInfoBaseFields *g_fields = nullptr;
70 }
71 
72 void HostInfoBase::Initialize() { g_fields = new HostInfoBaseFields(); }
73 
74 void HostInfoBase::Terminate() {
75   delete g_fields;
76   g_fields = nullptr;
77 }
78 
79 llvm::StringRef HostInfoBase::GetTargetTriple() {
80   static llvm::once_flag g_once_flag;
81   llvm::call_once(g_once_flag, []() {
82     g_fields->m_host_triple =
83         HostInfo::GetArchitecture().GetTriple().getTriple();
84   });
85   return g_fields->m_host_triple;
86 }
87 
88 const ArchSpec &HostInfoBase::GetArchitecture(ArchitectureKind arch_kind) {
89   static llvm::once_flag g_once_flag;
90   llvm::call_once(g_once_flag, []() {
91     HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32,
92                                              g_fields->m_host_arch_64);
93   });
94 
95   // If an explicit 32 or 64-bit architecture was requested, return that.
96   if (arch_kind == eArchKind32)
97     return g_fields->m_host_arch_32;
98   if (arch_kind == eArchKind64)
99     return g_fields->m_host_arch_64;
100 
101   // Otherwise prefer the 64-bit architecture if it is valid.
102   return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64
103                                               : g_fields->m_host_arch_32;
104 }
105 
106 llvm::Optional<HostInfoBase::ArchitectureKind> HostInfoBase::ParseArchitectureKind(llvm::StringRef kind) {
107   return llvm::StringSwitch<llvm::Optional<ArchitectureKind>>(kind)
108       .Case(LLDB_ARCH_DEFAULT, eArchKindDefault)
109       .Case(LLDB_ARCH_DEFAULT_32BIT, eArchKind32)
110       .Case(LLDB_ARCH_DEFAULT_64BIT, eArchKind64)
111       .Default(llvm::None);
112 }
113 
114 bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) {
115   file_spec.Clear();
116 
117 #if defined(LLDB_DISABLE_PYTHON)
118   if (type == lldb::ePathTypePythonDir)
119     return false;
120 #endif
121 
122   FileSpec *result = nullptr;
123   switch (type) {
124   case lldb::ePathTypeLLDBShlibDir: {
125     static llvm::once_flag g_once_flag;
126     static bool success = false;
127     llvm::call_once(g_once_flag, []() {
128       success =
129           HostInfo::ComputeSharedLibraryDirectory(g_fields->m_lldb_so_dir);
130       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
131       if (log)
132         log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'",
133                     g_fields->m_lldb_so_dir.GetPath().c_str());
134     });
135     if (success)
136       result = &g_fields->m_lldb_so_dir;
137   } break;
138   case lldb::ePathTypeSupportExecutableDir: {
139     static llvm::once_flag g_once_flag;
140     static bool success = false;
141     llvm::call_once(g_once_flag, []() {
142       success = HostInfo::ComputeSupportExeDirectory(
143           g_fields->m_lldb_support_exe_dir);
144       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
145       if (log)
146         log->Printf(
147             "HostInfoBase::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'",
148             g_fields->m_lldb_support_exe_dir.GetPath().c_str());
149     });
150     if (success)
151       result = &g_fields->m_lldb_support_exe_dir;
152   } break;
153   case lldb::ePathTypeHeaderDir: {
154     static llvm::once_flag g_once_flag;
155     static bool success = false;
156     llvm::call_once(g_once_flag, []() {
157       success = HostInfo::ComputeHeaderDirectory(g_fields->m_lldb_headers_dir);
158       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
159       if (log)
160         log->Printf("HostInfoBase::GetLLDBPath(ePathTypeHeaderDir) => '%s'",
161                     g_fields->m_lldb_headers_dir.GetPath().c_str());
162     });
163     if (success)
164       result = &g_fields->m_lldb_headers_dir;
165   } break;
166   case lldb::ePathTypePythonDir: {
167     static llvm::once_flag g_once_flag;
168     static bool success = false;
169     llvm::call_once(g_once_flag, []() {
170       success = HostInfo::ComputePythonDirectory(g_fields->m_lldb_python_dir);
171       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
172       if (log)
173         log->Printf("HostInfoBase::GetLLDBPath(ePathTypePythonDir) => '%s'",
174                     g_fields->m_lldb_python_dir.GetPath().c_str());
175     });
176     if (success)
177       result = &g_fields->m_lldb_python_dir;
178   } break;
179   case lldb::ePathTypeClangDir: {
180     static llvm::once_flag g_once_flag;
181     static bool success = false;
182     llvm::call_once(g_once_flag, []() {
183       success =
184           HostInfo::ComputeClangDirectory(g_fields->m_lldb_clang_resource_dir);
185       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
186       if (log)
187         log->Printf(
188             "HostInfoBase::GetLLDBPath(ePathTypeClangResourceDir) => '%s'",
189             g_fields->m_lldb_clang_resource_dir.GetPath().c_str());
190     });
191     if (success)
192       result = &g_fields->m_lldb_clang_resource_dir;
193   } break;
194   case lldb::ePathTypeLLDBSystemPlugins: {
195     static llvm::once_flag g_once_flag;
196     static bool success = false;
197     llvm::call_once(g_once_flag, []() {
198       success = HostInfo::ComputeSystemPluginsDirectory(
199           g_fields->m_lldb_system_plugin_dir);
200       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
201       if (log)
202         log->Printf(
203             "HostInfoBase::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'",
204             g_fields->m_lldb_system_plugin_dir.GetPath().c_str());
205     });
206     if (success)
207       result = &g_fields->m_lldb_system_plugin_dir;
208   } break;
209   case lldb::ePathTypeLLDBUserPlugins: {
210     static llvm::once_flag g_once_flag;
211     static bool success = false;
212     llvm::call_once(g_once_flag, []() {
213       success = HostInfo::ComputeUserPluginsDirectory(
214           g_fields->m_lldb_user_plugin_dir);
215       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
216       if (log)
217         log->Printf(
218             "HostInfoBase::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'",
219             g_fields->m_lldb_user_plugin_dir.GetPath().c_str());
220     });
221     if (success)
222       result = &g_fields->m_lldb_user_plugin_dir;
223   } break;
224   case lldb::ePathTypeLLDBTempSystemDir: {
225     static llvm::once_flag g_once_flag;
226     static bool success = false;
227     llvm::call_once(g_once_flag, []() {
228       success = HostInfo::ComputeProcessTempFileDirectory(
229           g_fields->m_lldb_process_tmp_dir);
230       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
231       if (log)
232         log->Printf(
233             "HostInfoBase::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'",
234             g_fields->m_lldb_process_tmp_dir.GetPath().c_str());
235     });
236     if (success)
237       result = &g_fields->m_lldb_process_tmp_dir;
238   } break;
239   case lldb::ePathTypeGlobalLLDBTempSystemDir: {
240     static llvm::once_flag g_once_flag;
241     static bool success = false;
242     llvm::call_once(g_once_flag, []() {
243       success = HostInfo::ComputeGlobalTempFileDirectory(
244           g_fields->m_lldb_global_tmp_dir);
245       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
246       if (log)
247         log->Printf("HostInfoBase::GetLLDBPath("
248                     "ePathTypeGlobalLLDBTempSystemDir) => '%s'",
249                     g_fields->m_lldb_global_tmp_dir.GetPath().c_str());
250     });
251     if (success)
252       result = &g_fields->m_lldb_global_tmp_dir;
253   } break;
254   }
255 
256   if (!result)
257     return false;
258   file_spec = *result;
259   return true;
260 }
261 
262 ArchSpec HostInfoBase::GetAugmentedArchSpec(llvm::StringRef triple) {
263   if (triple.empty())
264     return ArchSpec();
265   llvm::Triple normalized_triple(llvm::Triple::normalize(triple));
266   if (!ArchSpec::ContainsOnlyArch(normalized_triple))
267     return ArchSpec(triple);
268 
269   if (auto kind = HostInfo::ParseArchitectureKind(triple))
270     return HostInfo::GetArchitecture(*kind);
271 
272   llvm::Triple host_triple(llvm::sys::getDefaultTargetTriple());
273 
274   if (normalized_triple.getVendorName().empty())
275     normalized_triple.setVendor(host_triple.getVendor());
276   if (normalized_triple.getOSName().empty())
277     normalized_triple.setOS(host_triple.getOS());
278   if (normalized_triple.getEnvironmentName().empty())
279     normalized_triple.setEnvironment(host_triple.getEnvironment());
280   return ArchSpec(normalized_triple);
281 }
282 
283 bool HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec) {
284   // To get paths related to LLDB we get the path to the executable that
285   // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB".
286   // On other posix systems, we will get .../lib(64|32)?/liblldb.so.
287 
288   FileSpec lldb_file_spec(
289       Host::GetModuleFileSpecForHostAddress(reinterpret_cast<void *>(
290           reinterpret_cast<intptr_t>(HostInfoBase::GetLLDBPath))));
291 
292   // This is necessary because when running the testsuite the shlib might be a
293   // symbolic link inside the Python resource dir.
294   FileSystem::ResolveSymbolicLink(lldb_file_spec, lldb_file_spec);
295 
296   // Remove the filename so that this FileSpec only represents the directory.
297   file_spec.GetDirectory() = lldb_file_spec.GetDirectory();
298 
299   return (bool)file_spec.GetDirectory();
300 }
301 
302 bool HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) {
303   return GetLLDBPath(lldb::ePathTypeLLDBShlibDir, file_spec);
304 }
305 
306 bool HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec) {
307   FileSpec temp_file_spec;
308   if (!HostInfo::ComputeGlobalTempFileDirectory(temp_file_spec))
309     return false;
310 
311   std::string pid_str{llvm::to_string(Host::GetCurrentProcessID())};
312   temp_file_spec.AppendPathComponent(pid_str);
313   if (llvm::sys::fs::create_directory(temp_file_spec.GetPath()))
314     return false;
315 
316   file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
317   return true;
318 }
319 
320 bool HostInfoBase::ComputeTempFileBaseDirectory(FileSpec &file_spec) {
321   llvm::SmallVector<char, 16> tmpdir;
322   llvm::sys::path::system_temp_directory(/*ErasedOnReboot*/ true, tmpdir);
323   file_spec = FileSpec(std::string(tmpdir.data(), tmpdir.size()), true);
324   return true;
325 }
326 
327 bool HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) {
328   file_spec.Clear();
329 
330   FileSpec temp_file_spec;
331   if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec))
332     return false;
333 
334   temp_file_spec.AppendPathComponent("lldb");
335   if (llvm::sys::fs::create_directory(temp_file_spec.GetPath()))
336     return false;
337 
338   file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
339   return true;
340 }
341 
342 bool HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec) {
343   // TODO(zturner): Figure out how to compute the header directory for all
344   // platforms.
345   return false;
346 }
347 
348 bool HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec) {
349   // TODO(zturner): Figure out how to compute the system plugins directory for
350   // all platforms.
351   return false;
352 }
353 
354 bool HostInfoBase::ComputeClangDirectory(FileSpec &file_spec) { return false; }
355 
356 bool HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) {
357   // TODO(zturner): Figure out how to compute the user plugins directory for all
358   // platforms.
359   return false;
360 }
361 
362 void HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32,
363                                                   ArchSpec &arch_64) {
364   llvm::Triple triple(llvm::sys::getProcessTriple());
365 
366   arch_32.Clear();
367   arch_64.Clear();
368 
369   switch (triple.getArch()) {
370   default:
371     arch_32.SetTriple(triple);
372     break;
373 
374   case llvm::Triple::aarch64:
375   case llvm::Triple::ppc64:
376   case llvm::Triple::ppc64le:
377   case llvm::Triple::x86_64:
378     arch_64.SetTriple(triple);
379     arch_32.SetTriple(triple.get32BitArchVariant());
380     break;
381 
382   case llvm::Triple::mips64:
383   case llvm::Triple::mips64el:
384   case llvm::Triple::sparcv9:
385   case llvm::Triple::systemz:
386     arch_64.SetTriple(triple);
387     break;
388   }
389 }
390