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