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.GetDirectory().GetCString(), 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_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 uint32_t
84 HostInfoBase::GetNumberCPUS()
85 {
86     static std::once_flag g_once_flag;
87     std::call_once(g_once_flag,  []() {
88         g_fields->m_number_cpus = std::thread::hardware_concurrency();
89     });
90     return g_fields->m_number_cpus;
91 }
92 
93 uint32_t
94 HostInfoBase::GetMaxThreadNameLength()
95 {
96     return 0;
97 }
98 
99 llvm::StringRef
100 HostInfoBase::GetVendorString()
101 {
102     static std::once_flag g_once_flag;
103     std::call_once(g_once_flag,  []() {
104         g_fields->m_vendor_string = std::move(HostInfo::GetArchitecture().GetTriple().getVendorName().str());
105     });
106     return g_fields->m_vendor_string;
107 }
108 
109 llvm::StringRef
110 HostInfoBase::GetOSString()
111 {
112     static std::once_flag g_once_flag;
113     std::call_once(g_once_flag,  []() {
114         g_fields->m_os_string = std::move(HostInfo::GetArchitecture().GetTriple().getOSName());
115     });
116     return g_fields->m_os_string;
117 }
118 
119 llvm::StringRef
120 HostInfoBase::GetTargetTriple()
121 {
122     static std::once_flag g_once_flag;
123     std::call_once(g_once_flag,  []() {
124         g_fields->m_host_triple = HostInfo::GetArchitecture().GetTriple().getTriple();
125     });
126     return g_fields->m_host_triple;
127 }
128 
129 const ArchSpec &
130 HostInfoBase::GetArchitecture(ArchitectureKind arch_kind)
131 {
132     static std::once_flag g_once_flag;
133     std::call_once(g_once_flag,  []() {
134         HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32, g_fields->m_host_arch_64);
135     });
136 
137     // If an explicit 32 or 64-bit architecture was requested, return that.
138     if (arch_kind == eArchKind32)
139         return g_fields->m_host_arch_32;
140     if (arch_kind == eArchKind64)
141         return g_fields->m_host_arch_64;
142 
143     // Otherwise prefer the 64-bit architecture if it is valid.
144     return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64 : g_fields->m_host_arch_32;
145 }
146 
147 bool
148 HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec)
149 {
150     file_spec.Clear();
151 
152 #if defined(LLDB_DISABLE_PYTHON)
153     if (type == lldb::ePathTypePythonDir)
154         return false;
155 #endif
156 
157     FileSpec *result = nullptr;
158     switch (type)
159     {
160         case lldb::ePathTypeLLDBShlibDir:
161             {
162                 static std::once_flag g_once_flag;
163                 static bool success = false;
164                 std::call_once(g_once_flag,  []() {
165                     success = HostInfo::ComputeSharedLibraryDirectory (g_fields->m_lldb_so_dir);
166                     Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
167                     if (log)
168                         log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'", g_fields->m_lldb_so_dir.GetPath().c_str());
169                 });
170                 if (success)
171                     result = &g_fields->m_lldb_so_dir;
172             }
173             break;
174         case lldb::ePathTypeSupportExecutableDir:
175             {
176                 static std::once_flag g_once_flag;
177                 static bool success = false;
178                 std::call_once(g_once_flag,  []() {
179                     success = HostInfo::ComputeSupportExeDirectory (g_fields->m_lldb_support_exe_dir);
180                     Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
181                     if (log)
182                         log->Printf("HostInfoBase::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'",
183                                     g_fields->m_lldb_support_exe_dir.GetPath().c_str());
184                 });
185                 if (success)
186                     result = &g_fields->m_lldb_support_exe_dir;
187             }
188             break;
189         case lldb::ePathTypeHeaderDir:
190             {
191                 static std::once_flag g_once_flag;
192                 static bool success = false;
193                 std::call_once(g_once_flag,  []() {
194                     success = HostInfo::ComputeHeaderDirectory (g_fields->m_lldb_headers_dir);
195                     Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
196                     if (log)
197                         log->Printf("HostInfoBase::GetLLDBPath(ePathTypeHeaderDir) => '%s'", g_fields->m_lldb_headers_dir.GetPath().c_str());
198                 });
199                 if (success)
200                     result = &g_fields->m_lldb_headers_dir;
201             }
202             break;
203         case lldb::ePathTypePythonDir:
204             {
205                 static std::once_flag g_once_flag;
206                 static bool success = false;
207                 std::call_once(g_once_flag,  []() {
208                     success = HostInfo::ComputePythonDirectory (g_fields->m_lldb_python_dir);
209                     Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
210                     if (log)
211                         log->Printf("HostInfoBase::GetLLDBPath(ePathTypePythonDir) => '%s'", g_fields->m_lldb_python_dir.GetPath().c_str());
212                 });
213                 if (success)
214                     result = &g_fields->m_lldb_python_dir;
215             }
216             break;
217         case lldb::ePathTypeClangDir:
218             {
219                 static std::once_flag g_once_flag;
220                 static bool success = false;
221                 std::call_once(g_once_flag,  []() {
222                     success = HostInfo::ComputeClangDirectory (g_fields->m_lldb_clang_resource_dir);
223                     Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
224                     if (log)
225                         log->Printf("HostInfoBase::GetLLDBPath(ePathTypeClangResourceDir) => '%s'", g_fields->m_lldb_clang_resource_dir.GetPath().c_str());
226                 });
227                 if (success)
228                     result = &g_fields->m_lldb_clang_resource_dir;
229             }
230             break;
231         case lldb::ePathTypeLLDBSystemPlugins:
232             {
233                 static std::once_flag g_once_flag;
234                 static bool success = false;
235                 std::call_once(g_once_flag,  []() {
236                     success = HostInfo::ComputeSystemPluginsDirectory (g_fields->m_lldb_system_plugin_dir);
237                     Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
238                     if (log)
239                         log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'",
240                                     g_fields->m_lldb_system_plugin_dir.GetPath().c_str());
241                 });
242                 if (success)
243                     result = &g_fields->m_lldb_system_plugin_dir;
244             }
245             break;
246         case lldb::ePathTypeLLDBUserPlugins:
247             {
248                 static std::once_flag g_once_flag;
249                 static bool success = false;
250                 std::call_once(g_once_flag,  []() {
251                     success = HostInfo::ComputeUserPluginsDirectory (g_fields->m_lldb_user_plugin_dir);
252                     Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
253                     if (log)
254                         log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'",
255                                     g_fields->m_lldb_user_plugin_dir.GetPath().c_str());
256                 });
257                 if (success)
258                     result = &g_fields->m_lldb_user_plugin_dir;
259             }
260             break;
261         case lldb::ePathTypeLLDBTempSystemDir:
262             {
263                 static std::once_flag g_once_flag;
264                 static bool success = false;
265                 std::call_once(g_once_flag,  []() {
266                     success = HostInfo::ComputeTempFileDirectory (g_fields->m_lldb_tmp_dir);
267                     Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
268                     if (log)
269                         log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", g_fields->m_lldb_tmp_dir.GetPath().c_str());
270                 });
271                 if (success)
272                     result = &g_fields->m_lldb_tmp_dir;
273             }
274             break;
275     }
276 
277     if (!result)
278         return false;
279     file_spec = *result;
280     return true;
281 }
282 
283 bool
284 HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec)
285 {
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 *>(reinterpret_cast<intptr_t>(HostInfoBase::GetLLDBPath))));
294 
295     // Remove the filename so that this FileSpec only represents the directory.
296     file_spec.GetDirectory() = lldb_file_spec.GetDirectory();
297 
298     return (bool)file_spec.GetDirectory();
299 }
300 
301 bool
302 HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec)
303 {
304     return GetLLDBPath(lldb::ePathTypeLLDBShlibDir, file_spec);
305 }
306 
307 bool
308 HostInfoBase::ComputeTempFileDirectory(FileSpec &file_spec)
309 {
310     const char *tmpdir_cstr = getenv("TMPDIR");
311     if (tmpdir_cstr == NULL)
312     {
313         tmpdir_cstr = getenv("TMP");
314         if (tmpdir_cstr == NULL)
315             tmpdir_cstr = getenv("TEMP");
316     }
317     if (!tmpdir_cstr)
318         return false;
319 
320     FileSpec temp_file_spec(tmpdir_cstr, false);
321     temp_file_spec.AppendPathComponent("lldb");
322     if (!FileSystem::MakeDirectory(temp_file_spec.GetPath().c_str(), eFilePermissionsDirectoryDefault).Success())
323         return false;
324 
325     std::string pid_str;
326     llvm::raw_string_ostream pid_stream(pid_str);
327     pid_stream << Host::GetCurrentProcessID();
328     temp_file_spec.AppendPathComponent(pid_stream.str().c_str());
329     std::string final_path = temp_file_spec.GetPath();
330     if (!FileSystem::MakeDirectory(final_path.c_str(), eFilePermissionsDirectoryDefault).Success())
331         return false;
332 
333     // Make an atexit handler to clean up the process specify LLDB temp dir
334     // and all of its contents.
335     ::atexit(CleanupProcessSpecificLLDBTempDir);
336     file_spec.GetDirectory().SetCStringWithLength(final_path.c_str(), final_path.size());
337     return true;
338 }
339 
340 bool
341 HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec)
342 {
343     // TODO(zturner): Figure out how to compute the header directory for all platforms.
344     return false;
345 }
346 
347 bool
348 HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec)
349 {
350     // TODO(zturner): Figure out how to compute the system plugins directory for all platforms.
351     return false;
352 }
353 
354 bool
355 HostInfoBase::ComputeClangDirectory(FileSpec &file_spec)
356 {
357     return false;
358 }
359 
360 bool
361 HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec)
362 {
363     // TODO(zturner): Figure out how to compute the user plugins directory for all platforms.
364     return false;
365 }
366 
367 void
368 HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64)
369 {
370     llvm::Triple triple(llvm::sys::getProcessTriple());
371 
372     arch_32.Clear();
373     arch_64.Clear();
374 
375     switch (triple.getArch())
376     {
377         default:
378             arch_32.SetTriple(triple);
379             break;
380 
381         case llvm::Triple::ppc64:
382         case llvm::Triple::x86_64:
383             arch_64.SetTriple(triple);
384             arch_32.SetTriple(triple.get32BitArchVariant());
385             break;
386 
387         case llvm::Triple::aarch64:
388         case llvm::Triple::mips64:
389         case llvm::Triple::sparcv9:
390             arch_64.SetTriple(triple);
391             break;
392     }
393 }
394