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