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