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