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