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
CleanupProcessSpecificLLDBTempDir()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
Initialize()79 HostInfoBase::Initialize()
80 {
81 g_fields = new HostInfoBaseFields();
82 }
83
84 uint32_t
GetNumberCPUS()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
GetMaxThreadNameLength()95 HostInfoBase::GetMaxThreadNameLength()
96 {
97 return 0;
98 }
99
100 llvm::StringRef
GetVendorString()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 = std::move(HostInfo::GetArchitecture().GetTriple().getVendorName().str());
106 });
107 return g_fields->m_vendor_string;
108 }
109
110 llvm::StringRef
GetOSString()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
GetTargetTriple()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 &
GetArchitecture(ArchitectureKind arch_kind)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
GetLLDBPath(lldb::PathType type,FileSpec & file_spec)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
ComputeSharedLibraryDirectory(FileSpec & file_spec)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 // Remove the filename so that this FileSpec only represents the directory.
311 file_spec.GetDirectory() = lldb_file_spec.GetDirectory();
312
313 return (bool)file_spec.GetDirectory();
314 }
315
316 bool
ComputeSupportExeDirectory(FileSpec & file_spec)317 HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec)
318 {
319 return GetLLDBPath(lldb::ePathTypeLLDBShlibDir, file_spec);
320 }
321
322 bool
ComputeProcessTempFileDirectory(FileSpec & file_spec)323 HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec)
324 {
325 FileSpec temp_file_spec;
326 if (!HostInfo::ComputeGlobalTempFileDirectory(temp_file_spec))
327 return false;
328
329 std::string pid_str{std::to_string(Host::GetCurrentProcessID())};
330 temp_file_spec.AppendPathComponent(pid_str);
331 if (!FileSystem::MakeDirectory(temp_file_spec, eFilePermissionsDirectoryDefault).Success())
332 return false;
333
334 // Make an atexit handler to clean up the process specify LLDB temp dir
335 // and all of its contents.
336 ::atexit(CleanupProcessSpecificLLDBTempDir);
337 file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
338 return true;
339 }
340
341 bool
ComputeTempFileBaseDirectory(FileSpec & file_spec)342 HostInfoBase::ComputeTempFileBaseDirectory(FileSpec &file_spec)
343 {
344 file_spec.Clear();
345
346 const char *tmpdir_cstr = getenv("TMPDIR");
347 if (tmpdir_cstr == nullptr)
348 {
349 tmpdir_cstr = getenv("TMP");
350 if (tmpdir_cstr == nullptr)
351 tmpdir_cstr = getenv("TEMP");
352 }
353 if (!tmpdir_cstr)
354 return false;
355
356 file_spec = FileSpec(tmpdir_cstr, false);
357 return true;
358 }
359
360 bool
ComputeGlobalTempFileDirectory(FileSpec & file_spec)361 HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec)
362 {
363 file_spec.Clear();
364
365 FileSpec temp_file_spec;
366 if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec))
367 return false;
368
369 temp_file_spec.AppendPathComponent("lldb");
370 if (!FileSystem::MakeDirectory(temp_file_spec, eFilePermissionsDirectoryDefault).Success())
371 return false;
372
373 file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
374 return true;
375 }
376
377 bool
ComputeHeaderDirectory(FileSpec & file_spec)378 HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec)
379 {
380 // TODO(zturner): Figure out how to compute the header directory for all platforms.
381 return false;
382 }
383
384 bool
ComputeSystemPluginsDirectory(FileSpec & file_spec)385 HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec)
386 {
387 // TODO(zturner): Figure out how to compute the system plugins directory for all platforms.
388 return false;
389 }
390
391 bool
ComputeClangDirectory(FileSpec & file_spec)392 HostInfoBase::ComputeClangDirectory(FileSpec &file_spec)
393 {
394 return false;
395 }
396
397 bool
ComputeUserPluginsDirectory(FileSpec & file_spec)398 HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec)
399 {
400 // TODO(zturner): Figure out how to compute the user plugins directory for all platforms.
401 return false;
402 }
403
404 void
ComputeHostArchitectureSupport(ArchSpec & arch_32,ArchSpec & arch_64)405 HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64)
406 {
407 llvm::Triple triple(llvm::sys::getProcessTriple());
408
409 arch_32.Clear();
410 arch_64.Clear();
411
412 switch (triple.getArch())
413 {
414 default:
415 arch_32.SetTriple(triple);
416 break;
417
418 case llvm::Triple::ppc64:
419 case llvm::Triple::x86_64:
420 arch_64.SetTriple(triple);
421 arch_32.SetTriple(triple.get32BitArchVariant());
422 break;
423
424 case llvm::Triple::aarch64:
425 case llvm::Triple::mips64:
426 case llvm::Triple::mips64el:
427 case llvm::Triple::sparcv9:
428 arch_64.SetTriple(triple);
429 break;
430 }
431 }
432