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