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