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/Path.h" 24 #include "llvm/Support/raw_ostream.h" 25 26 #include <thread> 27 #include <mutex> // std::once 28 29 using namespace lldb; 30 using namespace lldb_private; 31 32 namespace 33 { 34 void 35 CleanupProcessSpecificLLDBTempDir() 36 { 37 // Get the process specific LLDB temporary directory and delete it. 38 FileSpec tmpdir_file_spec; 39 if (!HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) 40 return; 41 42 // Remove the LLDB temporary directory if we have one. Set "recurse" to 43 // true to all files that were created for the LLDB process can be cleaned up. 44 FileSystem::DeleteDirectory(tmpdir_file_spec, true); 45 } 46 47 //---------------------------------------------------------------------- 48 // The HostInfoBaseFields is a work around for windows not supporting 49 // static variables correctly in a thread safe way. Really each of the 50 // variables in HostInfoBaseFields should live in the functions in which 51 // they are used and each one should be static, but the work around is 52 // in place to avoid this restriction. Ick. 53 //---------------------------------------------------------------------- 54 55 struct HostInfoBaseFields 56 { 57 uint32_t m_number_cpus; 58 std::string m_vendor_string; 59 std::string m_os_string; 60 std::string m_host_triple; 61 62 ArchSpec m_host_arch_32; 63 ArchSpec m_host_arch_64; 64 65 FileSpec m_lldb_so_dir; 66 FileSpec m_lldb_support_exe_dir; 67 FileSpec m_lldb_headers_dir; 68 FileSpec m_lldb_python_dir; 69 FileSpec m_lldb_clang_resource_dir; 70 FileSpec m_lldb_system_plugin_dir; 71 FileSpec m_lldb_user_plugin_dir; 72 FileSpec m_lldb_process_tmp_dir; 73 FileSpec m_lldb_global_tmp_dir; 74 }; 75 76 HostInfoBaseFields *g_fields = nullptr; 77 } 78 79 void 80 HostInfoBase::Initialize() 81 { 82 g_fields = new HostInfoBaseFields(); 83 } 84 85 uint32_t 86 HostInfoBase::GetNumberCPUS() 87 { 88 static std::once_flag g_once_flag; 89 std::call_once(g_once_flag, []() { 90 g_fields->m_number_cpus = std::thread::hardware_concurrency(); 91 }); 92 return g_fields->m_number_cpus; 93 } 94 95 uint32_t 96 HostInfoBase::GetMaxThreadNameLength() 97 { 98 return 0; 99 } 100 101 llvm::StringRef 102 HostInfoBase::GetVendorString() 103 { 104 static std::once_flag g_once_flag; 105 std::call_once(g_once_flag, []() { 106 g_fields->m_vendor_string = HostInfo::GetArchitecture().GetTriple().getVendorName().str(); 107 }); 108 return g_fields->m_vendor_string; 109 } 110 111 llvm::StringRef 112 HostInfoBase::GetOSString() 113 { 114 static std::once_flag g_once_flag; 115 std::call_once(g_once_flag, []() { 116 g_fields->m_os_string = std::move(HostInfo::GetArchitecture().GetTriple().getOSName()); 117 }); 118 return g_fields->m_os_string; 119 } 120 121 llvm::StringRef 122 HostInfoBase::GetTargetTriple() 123 { 124 static std::once_flag g_once_flag; 125 std::call_once(g_once_flag, []() { 126 g_fields->m_host_triple = HostInfo::GetArchitecture().GetTriple().getTriple(); 127 }); 128 return g_fields->m_host_triple; 129 } 130 131 const ArchSpec & 132 HostInfoBase::GetArchitecture(ArchitectureKind arch_kind) 133 { 134 static std::once_flag g_once_flag; 135 std::call_once(g_once_flag, []() { 136 HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32, g_fields->m_host_arch_64); 137 }); 138 139 // If an explicit 32 or 64-bit architecture was requested, return that. 140 if (arch_kind == eArchKind32) 141 return g_fields->m_host_arch_32; 142 if (arch_kind == eArchKind64) 143 return g_fields->m_host_arch_64; 144 145 // Otherwise prefer the 64-bit architecture if it is valid. 146 return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64 : g_fields->m_host_arch_32; 147 } 148 149 bool 150 HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) 151 { 152 file_spec.Clear(); 153 154 #if defined(LLDB_DISABLE_PYTHON) 155 if (type == lldb::ePathTypePythonDir) 156 return false; 157 #endif 158 159 FileSpec *result = nullptr; 160 switch (type) 161 { 162 case lldb::ePathTypeLLDBShlibDir: 163 { 164 static std::once_flag g_once_flag; 165 static bool success = false; 166 std::call_once(g_once_flag, []() { 167 success = HostInfo::ComputeSharedLibraryDirectory (g_fields->m_lldb_so_dir); 168 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 169 if (log) 170 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'", g_fields->m_lldb_so_dir.GetPath().c_str()); 171 }); 172 if (success) 173 result = &g_fields->m_lldb_so_dir; 174 } 175 break; 176 case lldb::ePathTypeSupportExecutableDir: 177 { 178 static std::once_flag g_once_flag; 179 static bool success = false; 180 std::call_once(g_once_flag, []() { 181 success = HostInfo::ComputeSupportExeDirectory (g_fields->m_lldb_support_exe_dir); 182 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 183 if (log) 184 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'", 185 g_fields->m_lldb_support_exe_dir.GetPath().c_str()); 186 }); 187 if (success) 188 result = &g_fields->m_lldb_support_exe_dir; 189 } 190 break; 191 case lldb::ePathTypeHeaderDir: 192 { 193 static std::once_flag g_once_flag; 194 static bool success = false; 195 std::call_once(g_once_flag, []() { 196 success = HostInfo::ComputeHeaderDirectory (g_fields->m_lldb_headers_dir); 197 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 198 if (log) 199 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeHeaderDir) => '%s'", g_fields->m_lldb_headers_dir.GetPath().c_str()); 200 }); 201 if (success) 202 result = &g_fields->m_lldb_headers_dir; 203 } 204 break; 205 case lldb::ePathTypePythonDir: 206 { 207 static std::once_flag g_once_flag; 208 static bool success = false; 209 std::call_once(g_once_flag, []() { 210 success = HostInfo::ComputePythonDirectory (g_fields->m_lldb_python_dir); 211 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 212 if (log) 213 log->Printf("HostInfoBase::GetLLDBPath(ePathTypePythonDir) => '%s'", g_fields->m_lldb_python_dir.GetPath().c_str()); 214 }); 215 if (success) 216 result = &g_fields->m_lldb_python_dir; 217 } 218 break; 219 case lldb::ePathTypeClangDir: 220 { 221 static std::once_flag g_once_flag; 222 static bool success = false; 223 std::call_once(g_once_flag, []() { 224 success = HostInfo::ComputeClangDirectory (g_fields->m_lldb_clang_resource_dir); 225 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 226 if (log) 227 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeClangResourceDir) => '%s'", g_fields->m_lldb_clang_resource_dir.GetPath().c_str()); 228 }); 229 if (success) 230 result = &g_fields->m_lldb_clang_resource_dir; 231 } 232 break; 233 case lldb::ePathTypeLLDBSystemPlugins: 234 { 235 static std::once_flag g_once_flag; 236 static bool success = false; 237 std::call_once(g_once_flag, []() { 238 success = HostInfo::ComputeSystemPluginsDirectory (g_fields->m_lldb_system_plugin_dir); 239 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 240 if (log) 241 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'", 242 g_fields->m_lldb_system_plugin_dir.GetPath().c_str()); 243 }); 244 if (success) 245 result = &g_fields->m_lldb_system_plugin_dir; 246 } 247 break; 248 case lldb::ePathTypeLLDBUserPlugins: 249 { 250 static std::once_flag g_once_flag; 251 static bool success = false; 252 std::call_once(g_once_flag, []() { 253 success = HostInfo::ComputeUserPluginsDirectory (g_fields->m_lldb_user_plugin_dir); 254 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 255 if (log) 256 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'", 257 g_fields->m_lldb_user_plugin_dir.GetPath().c_str()); 258 }); 259 if (success) 260 result = &g_fields->m_lldb_user_plugin_dir; 261 } 262 break; 263 case lldb::ePathTypeLLDBTempSystemDir: 264 { 265 static std::once_flag g_once_flag; 266 static bool success = false; 267 std::call_once(g_once_flag, []() { 268 success = HostInfo::ComputeProcessTempFileDirectory (g_fields->m_lldb_process_tmp_dir); 269 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 270 if (log) 271 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", g_fields->m_lldb_process_tmp_dir.GetPath().c_str()); 272 }); 273 if (success) 274 result = &g_fields->m_lldb_process_tmp_dir; 275 } 276 break; 277 case lldb::ePathTypeGlobalLLDBTempSystemDir: 278 { 279 static std::once_flag g_once_flag; 280 static bool success = false; 281 std::call_once(g_once_flag, []() { 282 success = HostInfo::ComputeGlobalTempFileDirectory (g_fields->m_lldb_global_tmp_dir); 283 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 284 if (log) 285 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeGlobalLLDBTempSystemDir) => '%s'", g_fields->m_lldb_global_tmp_dir.GetPath().c_str()); 286 }); 287 if (success) 288 result = &g_fields->m_lldb_global_tmp_dir; 289 } 290 break; 291 } 292 293 if (!result) 294 return false; 295 file_spec = *result; 296 return true; 297 } 298 299 bool 300 HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec) 301 { 302 // To get paths related to LLDB we get the path to the executable that 303 // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB", 304 // on linux this is assumed to be the "lldb" main executable. If LLDB on 305 // linux is actually in a shared library (liblldb.so) then this function will 306 // need to be modified to "do the right thing". 307 308 FileSpec lldb_file_spec( 309 Host::GetModuleFileSpecForHostAddress(reinterpret_cast<void *>(reinterpret_cast<intptr_t>(HostInfoBase::GetLLDBPath)))); 310 311 // This is necessary because when running the testsuite the shlib might be a symbolic link inside the Python resource dir. 312 FileSystem::ResolveSymbolicLink(lldb_file_spec, lldb_file_spec); 313 314 // Remove the filename so that this FileSpec only represents the directory. 315 file_spec.GetDirectory() = lldb_file_spec.GetDirectory(); 316 317 return (bool)file_spec.GetDirectory(); 318 } 319 320 bool 321 HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) 322 { 323 return GetLLDBPath(lldb::ePathTypeLLDBShlibDir, file_spec); 324 } 325 326 bool 327 HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec) 328 { 329 FileSpec temp_file_spec; 330 if (!HostInfo::ComputeGlobalTempFileDirectory(temp_file_spec)) 331 return false; 332 333 std::string pid_str{std::to_string(Host::GetCurrentProcessID())}; 334 temp_file_spec.AppendPathComponent(pid_str); 335 if (!FileSystem::MakeDirectory(temp_file_spec, eFilePermissionsDirectoryDefault).Success()) 336 return false; 337 338 // Make an atexit handler to clean up the process specify LLDB temp dir 339 // and all of its contents. 340 ::atexit(CleanupProcessSpecificLLDBTempDir); 341 file_spec.GetDirectory().SetCString(temp_file_spec.GetCString()); 342 return true; 343 } 344 345 bool 346 HostInfoBase::ComputeTempFileBaseDirectory(FileSpec &file_spec) 347 { 348 llvm::SmallVector<char, 16> tmpdir; 349 llvm::sys::path::system_temp_directory(/*ErasedOnReboot*/ true, tmpdir); 350 file_spec = FileSpec(std::string(tmpdir.data(), tmpdir.size()), true); 351 return true; 352 } 353 354 bool 355 HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) 356 { 357 file_spec.Clear(); 358 359 FileSpec temp_file_spec; 360 if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec)) 361 return false; 362 363 temp_file_spec.AppendPathComponent("lldb"); 364 if (!FileSystem::MakeDirectory(temp_file_spec, eFilePermissionsDirectoryDefault).Success()) 365 return false; 366 367 file_spec.GetDirectory().SetCString(temp_file_spec.GetCString()); 368 return true; 369 } 370 371 bool 372 HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec) 373 { 374 // TODO(zturner): Figure out how to compute the header directory for all platforms. 375 return false; 376 } 377 378 bool 379 HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec) 380 { 381 // TODO(zturner): Figure out how to compute the system plugins directory for all platforms. 382 return false; 383 } 384 385 bool 386 HostInfoBase::ComputeClangDirectory(FileSpec &file_spec) 387 { 388 return false; 389 } 390 391 bool 392 HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) 393 { 394 // TODO(zturner): Figure out how to compute the user plugins directory for all platforms. 395 return false; 396 } 397 398 void 399 HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64) 400 { 401 llvm::Triple triple(llvm::sys::getProcessTriple()); 402 403 arch_32.Clear(); 404 arch_64.Clear(); 405 406 switch (triple.getArch()) 407 { 408 default: 409 arch_32.SetTriple(triple); 410 break; 411 412 case llvm::Triple::ppc64: 413 case llvm::Triple::x86_64: 414 arch_64.SetTriple(triple); 415 arch_32.SetTriple(triple.get32BitArchVariant()); 416 break; 417 418 case llvm::Triple::aarch64: 419 case llvm::Triple::mips64: 420 case llvm::Triple::mips64el: 421 case llvm::Triple::sparcv9: 422 arch_64.SetTriple(triple); 423 break; 424 } 425 } 426