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/Host/FileSystem.h"
14 #include "lldb/Host/Host.h"
15 #include "lldb/Host/HostInfo.h"
16 #include "lldb/Host/HostInfoBase.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 bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) {
107   file_spec.Clear();
108 
109 #if defined(LLDB_DISABLE_PYTHON)
110   if (type == lldb::ePathTypePythonDir)
111     return false;
112 #endif
113 
114   FileSpec *result = nullptr;
115   switch (type) {
116   case lldb::ePathTypeLLDBShlibDir: {
117     static llvm::once_flag g_once_flag;
118     static bool success = false;
119     llvm::call_once(g_once_flag, []() {
120       success =
121           HostInfo::ComputeSharedLibraryDirectory(g_fields->m_lldb_so_dir);
122       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
123       if (log)
124         log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'",
125                     g_fields->m_lldb_so_dir.GetPath().c_str());
126     });
127     if (success)
128       result = &g_fields->m_lldb_so_dir;
129   } break;
130   case lldb::ePathTypeSupportExecutableDir: {
131     static llvm::once_flag g_once_flag;
132     static bool success = false;
133     llvm::call_once(g_once_flag, []() {
134       success = HostInfo::ComputeSupportExeDirectory(
135           g_fields->m_lldb_support_exe_dir);
136       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
137       if (log)
138         log->Printf(
139             "HostInfoBase::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'",
140             g_fields->m_lldb_support_exe_dir.GetPath().c_str());
141     });
142     if (success)
143       result = &g_fields->m_lldb_support_exe_dir;
144   } break;
145   case lldb::ePathTypeHeaderDir: {
146     static llvm::once_flag g_once_flag;
147     static bool success = false;
148     llvm::call_once(g_once_flag, []() {
149       success = HostInfo::ComputeHeaderDirectory(g_fields->m_lldb_headers_dir);
150       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
151       if (log)
152         log->Printf("HostInfoBase::GetLLDBPath(ePathTypeHeaderDir) => '%s'",
153                     g_fields->m_lldb_headers_dir.GetPath().c_str());
154     });
155     if (success)
156       result = &g_fields->m_lldb_headers_dir;
157   } break;
158   case lldb::ePathTypePythonDir: {
159     static llvm::once_flag g_once_flag;
160     static bool success = false;
161     llvm::call_once(g_once_flag, []() {
162       success = HostInfo::ComputePythonDirectory(g_fields->m_lldb_python_dir);
163       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
164       if (log)
165         log->Printf("HostInfoBase::GetLLDBPath(ePathTypePythonDir) => '%s'",
166                     g_fields->m_lldb_python_dir.GetPath().c_str());
167     });
168     if (success)
169       result = &g_fields->m_lldb_python_dir;
170   } break;
171   case lldb::ePathTypeClangDir: {
172     static llvm::once_flag g_once_flag;
173     static bool success = false;
174     llvm::call_once(g_once_flag, []() {
175       success =
176           HostInfo::ComputeClangDirectory(g_fields->m_lldb_clang_resource_dir);
177       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
178       if (log)
179         log->Printf(
180             "HostInfoBase::GetLLDBPath(ePathTypeClangResourceDir) => '%s'",
181             g_fields->m_lldb_clang_resource_dir.GetPath().c_str());
182     });
183     if (success)
184       result = &g_fields->m_lldb_clang_resource_dir;
185   } break;
186   case lldb::ePathTypeLLDBSystemPlugins: {
187     static llvm::once_flag g_once_flag;
188     static bool success = false;
189     llvm::call_once(g_once_flag, []() {
190       success = HostInfo::ComputeSystemPluginsDirectory(
191           g_fields->m_lldb_system_plugin_dir);
192       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
193       if (log)
194         log->Printf(
195             "HostInfoBase::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'",
196             g_fields->m_lldb_system_plugin_dir.GetPath().c_str());
197     });
198     if (success)
199       result = &g_fields->m_lldb_system_plugin_dir;
200   } break;
201   case lldb::ePathTypeLLDBUserPlugins: {
202     static llvm::once_flag g_once_flag;
203     static bool success = false;
204     llvm::call_once(g_once_flag, []() {
205       success = HostInfo::ComputeUserPluginsDirectory(
206           g_fields->m_lldb_user_plugin_dir);
207       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
208       if (log)
209         log->Printf(
210             "HostInfoBase::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'",
211             g_fields->m_lldb_user_plugin_dir.GetPath().c_str());
212     });
213     if (success)
214       result = &g_fields->m_lldb_user_plugin_dir;
215   } break;
216   case lldb::ePathTypeLLDBTempSystemDir: {
217     static llvm::once_flag g_once_flag;
218     static bool success = false;
219     llvm::call_once(g_once_flag, []() {
220       success = HostInfo::ComputeProcessTempFileDirectory(
221           g_fields->m_lldb_process_tmp_dir);
222       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
223       if (log)
224         log->Printf(
225             "HostInfoBase::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'",
226             g_fields->m_lldb_process_tmp_dir.GetPath().c_str());
227     });
228     if (success)
229       result = &g_fields->m_lldb_process_tmp_dir;
230   } break;
231   case lldb::ePathTypeGlobalLLDBTempSystemDir: {
232     static llvm::once_flag g_once_flag;
233     static bool success = false;
234     llvm::call_once(g_once_flag, []() {
235       success = HostInfo::ComputeGlobalTempFileDirectory(
236           g_fields->m_lldb_global_tmp_dir);
237       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
238       if (log)
239         log->Printf("HostInfoBase::GetLLDBPath("
240                     "ePathTypeGlobalLLDBTempSystemDir) => '%s'",
241                     g_fields->m_lldb_global_tmp_dir.GetPath().c_str());
242     });
243     if (success)
244       result = &g_fields->m_lldb_global_tmp_dir;
245   } break;
246   }
247 
248   if (!result)
249     return false;
250   file_spec = *result;
251   return true;
252 }
253 
254 ArchSpec HostInfoBase::GetAugmentedArchSpec(llvm::StringRef triple) {
255   if (triple.empty())
256     return ArchSpec();
257   llvm::Triple normalized_triple(llvm::Triple::normalize(triple));
258   if (!ArchSpec::ContainsOnlyArch(normalized_triple))
259     return ArchSpec(triple);
260 
261   llvm::Triple host_triple(llvm::sys::getDefaultTargetTriple());
262 
263   if (normalized_triple.getVendorName().empty())
264     normalized_triple.setVendor(host_triple.getVendor());
265   if (normalized_triple.getOSName().empty())
266     normalized_triple.setOS(host_triple.getOS());
267   if (normalized_triple.getEnvironmentName().empty())
268     normalized_triple.setEnvironment(host_triple.getEnvironment());
269   return ArchSpec(normalized_triple);
270 }
271 
272 bool HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec) {
273   // To get paths related to LLDB we get the path to the executable that
274   // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB",
275   // on linux this is assumed to be the "lldb" main executable. If LLDB on
276   // linux is actually in a shared library (liblldb.so) then this function will
277   // need to be modified to "do the right thing".
278 
279   FileSpec lldb_file_spec(
280       Host::GetModuleFileSpecForHostAddress(reinterpret_cast<void *>(
281           reinterpret_cast<intptr_t>(HostInfoBase::GetLLDBPath))));
282 
283   // This is necessary because when running the testsuite the shlib might be a
284   // symbolic link inside the Python resource dir.
285   FileSystem::ResolveSymbolicLink(lldb_file_spec, lldb_file_spec);
286 
287   // Remove the filename so that this FileSpec only represents the directory.
288   file_spec.GetDirectory() = lldb_file_spec.GetDirectory();
289 
290   return (bool)file_spec.GetDirectory();
291 }
292 
293 bool HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) {
294   return GetLLDBPath(lldb::ePathTypeLLDBShlibDir, file_spec);
295 }
296 
297 bool HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec) {
298   FileSpec temp_file_spec;
299   if (!HostInfo::ComputeGlobalTempFileDirectory(temp_file_spec))
300     return false;
301 
302   std::string pid_str{llvm::to_string(Host::GetCurrentProcessID())};
303   temp_file_spec.AppendPathComponent(pid_str);
304   if (llvm::sys::fs::create_directory(temp_file_spec.GetPath()))
305     return false;
306 
307   file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
308   return true;
309 }
310 
311 bool HostInfoBase::ComputeTempFileBaseDirectory(FileSpec &file_spec) {
312   llvm::SmallVector<char, 16> tmpdir;
313   llvm::sys::path::system_temp_directory(/*ErasedOnReboot*/ true, tmpdir);
314   file_spec = FileSpec(std::string(tmpdir.data(), tmpdir.size()), true);
315   return true;
316 }
317 
318 bool HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) {
319   file_spec.Clear();
320 
321   FileSpec temp_file_spec;
322   if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec))
323     return false;
324 
325   temp_file_spec.AppendPathComponent("lldb");
326   if (llvm::sys::fs::create_directory(temp_file_spec.GetPath()))
327     return false;
328 
329   file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
330   return true;
331 }
332 
333 bool HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec) {
334   // TODO(zturner): Figure out how to compute the header directory for all
335   // platforms.
336   return false;
337 }
338 
339 bool HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec) {
340   // TODO(zturner): Figure out how to compute the system plugins directory for
341   // all platforms.
342   return false;
343 }
344 
345 bool HostInfoBase::ComputeClangDirectory(FileSpec &file_spec) { return false; }
346 
347 bool HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) {
348   // TODO(zturner): Figure out how to compute the user plugins directory for all
349   // platforms.
350   return false;
351 }
352 
353 void HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32,
354                                                   ArchSpec &arch_64) {
355   llvm::Triple triple(llvm::sys::getProcessTriple());
356 
357   arch_32.Clear();
358   arch_64.Clear();
359 
360   switch (triple.getArch()) {
361   default:
362     arch_32.SetTriple(triple);
363     break;
364 
365   case llvm::Triple::aarch64:
366   case llvm::Triple::ppc64:
367   case llvm::Triple::x86_64:
368     arch_64.SetTriple(triple);
369     arch_32.SetTriple(triple.get32BitArchVariant());
370     break;
371 
372   case llvm::Triple::mips64:
373   case llvm::Triple::mips64el:
374   case llvm::Triple::sparcv9:
375   case llvm::Triple::systemz:
376     arch_64.SetTriple(triple);
377     break;
378   }
379 }
380