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