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 
27 using namespace lldb;
28 using namespace lldb_private;
29 
30 namespace
31 {
32 void
33 CleanupProcessSpecificLLDBTempDir()
34 {
35     // Get the process specific LLDB temporary directory and delete it.
36     FileSpec tmpdir_file_spec;
37     if (!HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
38         return;
39 
40     // Remove the LLDB temporary directory if we have one. Set "recurse" to
41     // true to all files that were created for the LLDB process can be cleaned up.
42     FileSystem::DeleteDirectory(tmpdir_file_spec.GetDirectory().GetCString(), true);
43 }
44 
45 struct HostInfoBaseFields
46 {
47     uint32_t m_number_cpus;
48     std::string m_vendor_string;
49     std::string m_os_string;
50     std::string m_host_triple;
51 
52     ArchSpec m_host_arch_32;
53     ArchSpec m_host_arch_64;
54 
55     FileSpec m_lldb_so_dir;
56     FileSpec m_lldb_support_exe_dir;
57     FileSpec m_lldb_headers_dir;
58     FileSpec m_lldb_python_dir;
59     FileSpec m_lldb_clang_resource_dir;
60     FileSpec m_lldb_system_plugin_dir;
61     FileSpec m_lldb_user_plugin_dir;
62     FileSpec m_lldb_tmp_dir;
63 };
64 
65 HostInfoBaseFields *g_fields = nullptr;
66 }
67 
68 #define COMPUTE_LLDB_PATH(compute_function, member_var)                                                                                    \
69     {                                                                                                                                      \
70         static bool is_initialized = false;                                                                                                \
71         static bool success = false;                                                                                                       \
72         if (!is_initialized)                                                                                                               \
73         {                                                                                                                                  \
74             is_initialized = true;                                                                                                         \
75             success = HostInfo::compute_function(member_var);                                                                              \
76         }                                                                                                                                  \
77         if (success)                                                                                                                       \
78             result = &member_var;                                                                                                          \
79     }
80 
81 void
82 HostInfoBase::Initialize()
83 {
84     g_fields = new HostInfoBaseFields();
85 }
86 
87 uint32_t
88 HostInfoBase::GetNumberCPUS()
89 {
90     static bool is_initialized = false;
91     if (!is_initialized)
92     {
93         g_fields->m_number_cpus = std::thread::hardware_concurrency();
94         is_initialized = true;
95     }
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 bool is_initialized = false;
110     if (!is_initialized)
111     {
112         const ArchSpec &host_arch = HostInfo::GetArchitecture();
113         const llvm::StringRef &str_ref = host_arch.GetTriple().getVendorName();
114         g_fields->m_vendor_string.assign(str_ref.begin(), str_ref.end());
115         is_initialized = true;
116     }
117     return g_fields->m_vendor_string;
118 }
119 
120 llvm::StringRef
121 HostInfoBase::GetOSString()
122 {
123     static bool is_initialized = false;
124     if (!is_initialized)
125     {
126         const ArchSpec &host_arch = HostInfo::GetArchitecture();
127         const llvm::StringRef &str_ref = host_arch.GetTriple().getOSName();
128         g_fields->m_os_string.assign(str_ref.begin(), str_ref.end());
129         is_initialized = true;
130     }
131     return g_fields->m_os_string;
132 }
133 
134 llvm::StringRef
135 HostInfoBase::GetTargetTriple()
136 {
137     static bool is_initialized = false;
138     if (!is_initialized)
139     {
140         const ArchSpec &host_arch = HostInfo::GetArchitecture();
141         g_fields->m_host_triple = host_arch.GetTriple().getTriple();
142         is_initialized = true;
143     }
144     return g_fields->m_host_triple;
145 }
146 
147 const ArchSpec &
148 HostInfoBase::GetArchitecture(ArchitectureKind arch_kind)
149 {
150     static bool is_initialized = false;
151     if (!is_initialized)
152     {
153         HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32, g_fields->m_host_arch_64);
154         is_initialized = true;
155     }
156 
157     // If an explicit 32 or 64-bit architecture was requested, return that.
158     if (arch_kind == eArchKind32)
159         return g_fields->m_host_arch_32;
160     if (arch_kind == eArchKind64)
161         return g_fields->m_host_arch_64;
162 
163     // Otherwise prefer the 64-bit architecture if it is valid.
164     return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64 : g_fields->m_host_arch_32;
165 }
166 
167 bool
168 HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec)
169 {
170     file_spec.Clear();
171 
172 #if defined(LLDB_DISABLE_PYTHON)
173     if (type == lldb::ePathTypePythonDir)
174         return false;
175 #endif
176 
177     Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
178     FileSpec *result = nullptr;
179     switch (type)
180     {
181         case lldb::ePathTypeLLDBShlibDir:
182             COMPUTE_LLDB_PATH(ComputeSharedLibraryDirectory, g_fields->m_lldb_so_dir)
183             if (log)
184                 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'", g_fields->m_lldb_so_dir.GetPath().c_str());
185             break;
186         case lldb::ePathTypeSupportExecutableDir:
187             COMPUTE_LLDB_PATH(ComputeSupportExeDirectory, g_fields->m_lldb_support_exe_dir)
188             if (log)
189                 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'",
190                             g_fields->m_lldb_support_exe_dir.GetPath().c_str());
191             break;
192         case lldb::ePathTypeHeaderDir:
193             COMPUTE_LLDB_PATH(ComputeHeaderDirectory, g_fields->m_lldb_headers_dir)
194             if (log)
195                 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeHeaderDir) => '%s'", g_fields->m_lldb_headers_dir.GetPath().c_str());
196             break;
197         case lldb::ePathTypePythonDir:
198             COMPUTE_LLDB_PATH(ComputePythonDirectory, g_fields->m_lldb_python_dir)
199             if (log)
200                 log->Printf("HostInfoBase::GetLLDBPath(ePathTypePythonDir) => '%s'", g_fields->m_lldb_python_dir.GetPath().c_str());
201             break;
202         case lldb::ePathTypeClangDir:
203             COMPUTE_LLDB_PATH(ComputeClangDirectory, g_fields->m_lldb_clang_resource_dir)
204             if (log)
205                 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeClangResourceDir) => '%s'", g_fields->m_lldb_clang_resource_dir.GetPath().c_str());
206             break;
207         case lldb::ePathTypeLLDBSystemPlugins:
208             COMPUTE_LLDB_PATH(ComputeSystemPluginsDirectory, g_fields->m_lldb_system_plugin_dir)
209             if (log)
210                 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'",
211                             g_fields->m_lldb_system_plugin_dir.GetPath().c_str());
212             break;
213         case lldb::ePathTypeLLDBUserPlugins:
214             COMPUTE_LLDB_PATH(ComputeUserPluginsDirectory, g_fields->m_lldb_user_plugin_dir)
215             if (log)
216                 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'",
217                             g_fields->m_lldb_user_plugin_dir.GetPath().c_str());
218             break;
219         case lldb::ePathTypeLLDBTempSystemDir:
220             COMPUTE_LLDB_PATH(ComputeTempFileDirectory, g_fields->m_lldb_tmp_dir)
221             if (log)
222                 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", g_fields->m_lldb_tmp_dir.GetPath().c_str());
223             break;
224     }
225 
226     if (!result)
227         return false;
228     file_spec = *result;
229     return true;
230 }
231 
232 bool
233 HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec)
234 {
235     // To get paths related to LLDB we get the path to the executable that
236     // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB",
237     // on linux this is assumed to be the "lldb" main executable. If LLDB on
238     // linux is actually in a shared library (liblldb.so) then this function will
239     // need to be modified to "do the right thing".
240 
241     FileSpec lldb_file_spec(
242         Host::GetModuleFileSpecForHostAddress(reinterpret_cast<void *>(reinterpret_cast<intptr_t>(HostInfoBase::GetLLDBPath))));
243 
244     // Remove the filename so that this FileSpec only represents the directory.
245     file_spec.GetDirectory() = lldb_file_spec.GetDirectory();
246 
247     return (bool)file_spec.GetDirectory();
248 }
249 
250 bool
251 HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec)
252 {
253     return GetLLDBPath(lldb::ePathTypeLLDBShlibDir, file_spec);
254 }
255 
256 bool
257 HostInfoBase::ComputeTempFileDirectory(FileSpec &file_spec)
258 {
259     const char *tmpdir_cstr = getenv("TMPDIR");
260     if (tmpdir_cstr == NULL)
261     {
262         tmpdir_cstr = getenv("TMP");
263         if (tmpdir_cstr == NULL)
264             tmpdir_cstr = getenv("TEMP");
265     }
266     if (!tmpdir_cstr)
267         return false;
268 
269     FileSpec temp_file_spec(tmpdir_cstr, false);
270     temp_file_spec.AppendPathComponent("lldb");
271     if (!FileSystem::MakeDirectory(temp_file_spec.GetPath().c_str(), eFilePermissionsDirectoryDefault).Success())
272         return false;
273 
274     std::string pid_str;
275     llvm::raw_string_ostream pid_stream(pid_str);
276     pid_stream << Host::GetCurrentProcessID();
277     temp_file_spec.AppendPathComponent(pid_stream.str().c_str());
278     std::string final_path = temp_file_spec.GetPath();
279     if (!FileSystem::MakeDirectory(final_path.c_str(), eFilePermissionsDirectoryDefault).Success())
280         return false;
281 
282     // Make an atexit handler to clean up the process specify LLDB temp dir
283     // and all of its contents.
284     ::atexit(CleanupProcessSpecificLLDBTempDir);
285     file_spec.GetDirectory().SetCStringWithLength(final_path.c_str(), final_path.size());
286     return true;
287 }
288 
289 bool
290 HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec)
291 {
292     // TODO(zturner): Figure out how to compute the header directory for all platforms.
293     return false;
294 }
295 
296 bool
297 HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec)
298 {
299     // TODO(zturner): Figure out how to compute the system plugins directory for all platforms.
300     return false;
301 }
302 
303 bool
304 HostInfoBase::ComputeClangDirectory(FileSpec &file_spec)
305 {
306     return false;
307 }
308 
309 bool
310 HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec)
311 {
312     // TODO(zturner): Figure out how to compute the user plugins directory for all platforms.
313     return false;
314 }
315 
316 void
317 HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64)
318 {
319     llvm::Triple triple(llvm::sys::getDefaultTargetTriple());
320 
321     arch_32.Clear();
322     arch_64.Clear();
323 
324     switch (triple.getArch())
325     {
326         default:
327             arch_32.SetTriple(triple);
328             break;
329 
330         case llvm::Triple::x86_64:
331             arch_64.SetTriple(triple);
332             arch_32.SetTriple(triple.get32BitArchVariant());
333             break;
334 
335         case llvm::Triple::aarch64:
336         case llvm::Triple::mips64:
337         case llvm::Triple::sparcv9:
338         case llvm::Triple::ppc64:
339             arch_64.SetTriple(triple);
340             break;
341     }
342 }
343