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 = std::move(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 // 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 317 HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) 318 { 319 return GetLLDBPath(lldb::ePathTypeLLDBShlibDir, file_spec); 320 } 321 322 bool 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 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 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 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 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 392 HostInfoBase::ComputeClangDirectory(FileSpec &file_spec) 393 { 394 return false; 395 } 396 397 bool 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 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