1 //===-- HostInfoBase.cpp --------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Host/Config.h" 10 11 #include "lldb/Host/FileSystem.h" 12 #include "lldb/Host/Host.h" 13 #include "lldb/Host/HostInfo.h" 14 #include "lldb/Host/HostInfoBase.h" 15 #include "lldb/Utility/ArchSpec.h" 16 #include "lldb/Utility/LLDBLog.h" 17 #include "lldb/Utility/Log.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 <optional> 30 #include <thread> 31 32 using namespace lldb; 33 using namespace lldb_private; 34 35 namespace { 36 /// Contains the state of the HostInfoBase plugin. 37 struct HostInfoBaseFields { 38 ~HostInfoBaseFields() { 39 if (FileSystem::Instance().Exists(m_lldb_process_tmp_dir)) { 40 // Remove the LLDB temporary directory if we have one. Set "recurse" to 41 // true to all files that were created for the LLDB process can be 42 // cleaned up. 43 llvm::sys::fs::remove_directories(m_lldb_process_tmp_dir.GetPath()); 44 } 45 } 46 47 llvm::once_flag m_host_triple_once; 48 llvm::Triple m_host_triple; 49 50 llvm::once_flag m_host_arch_once; 51 ArchSpec m_host_arch_32; 52 ArchSpec m_host_arch_64; 53 54 llvm::once_flag m_lldb_so_dir_once; 55 FileSpec m_lldb_so_dir; 56 llvm::once_flag m_lldb_support_exe_dir_once; 57 FileSpec m_lldb_support_exe_dir; 58 llvm::once_flag m_lldb_headers_dir_once; 59 FileSpec m_lldb_headers_dir; 60 llvm::once_flag m_lldb_clang_resource_dir_once; 61 FileSpec m_lldb_clang_resource_dir; 62 llvm::once_flag m_lldb_system_plugin_dir_once; 63 FileSpec m_lldb_system_plugin_dir; 64 llvm::once_flag m_lldb_user_plugin_dir_once; 65 FileSpec m_lldb_user_plugin_dir; 66 llvm::once_flag m_lldb_process_tmp_dir_once; 67 FileSpec m_lldb_process_tmp_dir; 68 llvm::once_flag m_lldb_global_tmp_dir_once; 69 FileSpec m_lldb_global_tmp_dir; 70 }; 71 } // namespace 72 73 static HostInfoBaseFields *g_fields = nullptr; 74 static HostInfoBase::SharedLibraryDirectoryHelper *g_shlib_dir_helper = nullptr; 75 76 void HostInfoBase::Initialize(SharedLibraryDirectoryHelper *helper) { 77 g_shlib_dir_helper = helper; 78 g_fields = new HostInfoBaseFields(); 79 } 80 81 void HostInfoBase::Terminate() { 82 g_shlib_dir_helper = nullptr; 83 delete g_fields; 84 g_fields = nullptr; 85 } 86 87 llvm::Triple HostInfoBase::GetTargetTriple() { 88 llvm::call_once(g_fields->m_host_triple_once, []() { 89 g_fields->m_host_triple = HostInfo::GetArchitecture().GetTriple(); 90 }); 91 return g_fields->m_host_triple; 92 } 93 94 const ArchSpec &HostInfoBase::GetArchitecture(ArchitectureKind arch_kind) { 95 llvm::call_once(g_fields->m_host_arch_once, []() { 96 HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32, 97 g_fields->m_host_arch_64); 98 }); 99 100 // If an explicit 32 or 64-bit architecture was requested, return that. 101 if (arch_kind == eArchKind32) 102 return g_fields->m_host_arch_32; 103 if (arch_kind == eArchKind64) 104 return g_fields->m_host_arch_64; 105 106 // Otherwise prefer the 64-bit architecture if it is valid. 107 return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64 108 : g_fields->m_host_arch_32; 109 } 110 111 std::optional<HostInfoBase::ArchitectureKind> 112 HostInfoBase::ParseArchitectureKind(llvm::StringRef kind) { 113 return llvm::StringSwitch<std::optional<ArchitectureKind>>(kind) 114 .Case(LLDB_ARCH_DEFAULT, eArchKindDefault) 115 .Case(LLDB_ARCH_DEFAULT_32BIT, eArchKind32) 116 .Case(LLDB_ARCH_DEFAULT_64BIT, eArchKind64) 117 .Default(std::nullopt); 118 } 119 120 FileSpec HostInfoBase::GetShlibDir() { 121 llvm::call_once(g_fields->m_lldb_so_dir_once, []() { 122 if (!HostInfo::ComputeSharedLibraryDirectory(g_fields->m_lldb_so_dir)) 123 g_fields->m_lldb_so_dir = FileSpec(); 124 Log *log = GetLog(LLDBLog::Host); 125 LLDB_LOG(log, "shlib dir -> `{0}`", g_fields->m_lldb_so_dir); 126 }); 127 return g_fields->m_lldb_so_dir; 128 } 129 130 FileSpec HostInfoBase::GetSupportExeDir() { 131 llvm::call_once(g_fields->m_lldb_support_exe_dir_once, []() { 132 if (!HostInfo::ComputeSupportExeDirectory(g_fields->m_lldb_support_exe_dir)) 133 g_fields->m_lldb_support_exe_dir = FileSpec(); 134 Log *log = GetLog(LLDBLog::Host); 135 LLDB_LOG(log, "support exe dir -> `{0}`", g_fields->m_lldb_support_exe_dir); 136 }); 137 return g_fields->m_lldb_support_exe_dir; 138 } 139 140 FileSpec HostInfoBase::GetHeaderDir() { 141 llvm::call_once(g_fields->m_lldb_headers_dir_once, []() { 142 if (!HostInfo::ComputeHeaderDirectory(g_fields->m_lldb_headers_dir)) 143 g_fields->m_lldb_headers_dir = FileSpec(); 144 Log *log = GetLog(LLDBLog::Host); 145 LLDB_LOG(log, "header dir -> `{0}`", g_fields->m_lldb_headers_dir); 146 }); 147 return g_fields->m_lldb_headers_dir; 148 } 149 150 FileSpec HostInfoBase::GetSystemPluginDir() { 151 llvm::call_once(g_fields->m_lldb_system_plugin_dir_once, []() { 152 if (!HostInfo::ComputeSystemPluginsDirectory( 153 g_fields->m_lldb_system_plugin_dir)) 154 g_fields->m_lldb_system_plugin_dir = FileSpec(); 155 Log *log = GetLog(LLDBLog::Host); 156 LLDB_LOG(log, "system plugin dir -> `{0}`", 157 g_fields->m_lldb_system_plugin_dir); 158 }); 159 return g_fields->m_lldb_system_plugin_dir; 160 } 161 162 FileSpec HostInfoBase::GetUserPluginDir() { 163 llvm::call_once(g_fields->m_lldb_user_plugin_dir_once, []() { 164 if (!HostInfo::ComputeUserPluginsDirectory( 165 g_fields->m_lldb_user_plugin_dir)) 166 g_fields->m_lldb_user_plugin_dir = FileSpec(); 167 Log *log = GetLog(LLDBLog::Host); 168 LLDB_LOG(log, "user plugin dir -> `{0}`", g_fields->m_lldb_user_plugin_dir); 169 }); 170 return g_fields->m_lldb_user_plugin_dir; 171 } 172 173 FileSpec HostInfoBase::GetProcessTempDir() { 174 llvm::call_once(g_fields->m_lldb_process_tmp_dir_once, []() { 175 if (!HostInfo::ComputeProcessTempFileDirectory( 176 g_fields->m_lldb_process_tmp_dir)) 177 g_fields->m_lldb_process_tmp_dir = FileSpec(); 178 Log *log = GetLog(LLDBLog::Host); 179 LLDB_LOG(log, "process temp dir -> `{0}`", 180 g_fields->m_lldb_process_tmp_dir); 181 }); 182 return g_fields->m_lldb_process_tmp_dir; 183 } 184 185 FileSpec HostInfoBase::GetGlobalTempDir() { 186 llvm::call_once(g_fields->m_lldb_global_tmp_dir_once, []() { 187 if (!HostInfo::ComputeGlobalTempFileDirectory( 188 g_fields->m_lldb_global_tmp_dir)) 189 g_fields->m_lldb_global_tmp_dir = FileSpec(); 190 191 Log *log = GetLog(LLDBLog::Host); 192 LLDB_LOG(log, "global temp dir -> `{0}`", g_fields->m_lldb_global_tmp_dir); 193 }); 194 return g_fields->m_lldb_global_tmp_dir; 195 } 196 197 ArchSpec HostInfoBase::GetAugmentedArchSpec(llvm::StringRef triple) { 198 if (triple.empty()) 199 return ArchSpec(); 200 llvm::Triple normalized_triple(llvm::Triple::normalize(triple)); 201 if (!ArchSpec::ContainsOnlyArch(normalized_triple)) 202 return ArchSpec(triple); 203 204 if (auto kind = HostInfo::ParseArchitectureKind(triple)) 205 return HostInfo::GetArchitecture(*kind); 206 207 llvm::Triple host_triple(llvm::sys::getDefaultTargetTriple()); 208 209 if (normalized_triple.getVendorName().empty()) 210 normalized_triple.setVendor(host_triple.getVendor()); 211 if (normalized_triple.getOSName().empty()) 212 normalized_triple.setOS(host_triple.getOS()); 213 if (normalized_triple.getEnvironmentName().empty() && 214 !host_triple.getEnvironmentName().empty()) 215 normalized_triple.setEnvironment(host_triple.getEnvironment()); 216 return ArchSpec(normalized_triple); 217 } 218 219 bool HostInfoBase::ComputePathRelativeToLibrary(FileSpec &file_spec, 220 llvm::StringRef dir) { 221 Log *log = GetLog(LLDBLog::Host); 222 223 FileSpec lldb_file_spec = GetShlibDir(); 224 if (!lldb_file_spec) 225 return false; 226 227 std::string raw_path = lldb_file_spec.GetPath(); 228 LLDB_LOGF(log, 229 "HostInfo::%s() attempting to " 230 "derive the path %s relative to liblldb install path: %s", 231 __FUNCTION__, dir.data(), raw_path.c_str()); 232 233 // Drop bin (windows) or lib 234 llvm::StringRef parent_path = llvm::sys::path::parent_path(raw_path); 235 if (parent_path.empty()) { 236 LLDB_LOGF(log, 237 "HostInfo::%s() failed to find liblldb within the shared " 238 "lib path", 239 __FUNCTION__); 240 return false; 241 } 242 243 raw_path = (parent_path + dir).str(); 244 LLDB_LOGF(log, "HostInfo::%s() derived the path as: %s", __FUNCTION__, 245 raw_path.c_str()); 246 file_spec.SetDirectory(raw_path); 247 return (bool)file_spec.GetDirectory(); 248 } 249 250 bool HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec) { 251 // To get paths related to LLDB we get the path to the executable that 252 // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB". 253 // On other posix systems, we will get .../lib(64|32)?/liblldb.so. 254 255 FileSpec lldb_file_spec(Host::GetModuleFileSpecForHostAddress( 256 reinterpret_cast<void *>(HostInfoBase::ComputeSharedLibraryDirectory))); 257 258 if (g_shlib_dir_helper) 259 g_shlib_dir_helper(lldb_file_spec); 260 261 // Remove the filename so that this FileSpec only represents the directory. 262 file_spec.SetDirectory(lldb_file_spec.GetDirectory()); 263 264 return (bool)file_spec.GetDirectory(); 265 } 266 267 bool HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) { 268 file_spec = GetShlibDir(); 269 return bool(file_spec); 270 } 271 272 bool HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec) { 273 FileSpec temp_file_spec; 274 if (!HostInfo::ComputeGlobalTempFileDirectory(temp_file_spec)) 275 return false; 276 277 std::string pid_str{llvm::to_string(Host::GetCurrentProcessID())}; 278 temp_file_spec.AppendPathComponent(pid_str); 279 if (llvm::sys::fs::create_directory(temp_file_spec.GetPath())) 280 return false; 281 282 file_spec.SetDirectory(temp_file_spec.GetPathAsConstString()); 283 return true; 284 } 285 286 bool HostInfoBase::ComputeTempFileBaseDirectory(FileSpec &file_spec) { 287 llvm::SmallVector<char, 16> tmpdir; 288 llvm::sys::path::system_temp_directory(/*ErasedOnReboot*/ true, tmpdir); 289 file_spec = FileSpec(std::string(tmpdir.data(), tmpdir.size())); 290 FileSystem::Instance().Resolve(file_spec); 291 return true; 292 } 293 294 bool HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) { 295 file_spec.Clear(); 296 297 FileSpec temp_file_spec; 298 if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec)) 299 return false; 300 301 temp_file_spec.AppendPathComponent("lldb"); 302 if (llvm::sys::fs::create_directory(temp_file_spec.GetPath())) 303 return false; 304 305 file_spec.SetDirectory(temp_file_spec.GetPathAsConstString()); 306 return true; 307 } 308 309 bool HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec) { 310 // TODO(zturner): Figure out how to compute the header directory for all 311 // platforms. 312 return false; 313 } 314 315 bool HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec) { 316 // TODO(zturner): Figure out how to compute the system plugins directory for 317 // all platforms. 318 return false; 319 } 320 321 bool HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) { 322 // TODO(zturner): Figure out how to compute the user plugins directory for 323 // all platforms. 324 return false; 325 } 326 327 void HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, 328 ArchSpec &arch_64) { 329 llvm::Triple triple(llvm::sys::getProcessTriple()); 330 331 arch_32.Clear(); 332 arch_64.Clear(); 333 334 switch (triple.getArch()) { 335 default: 336 arch_32.SetTriple(triple); 337 break; 338 339 case llvm::Triple::aarch64: 340 case llvm::Triple::ppc64: 341 case llvm::Triple::ppc64le: 342 case llvm::Triple::x86_64: 343 case llvm::Triple::riscv64: 344 case llvm::Triple::loongarch64: 345 arch_64.SetTriple(triple); 346 arch_32.SetTriple(triple.get32BitArchVariant()); 347 break; 348 349 case llvm::Triple::mips64: 350 case llvm::Triple::mips64el: 351 case llvm::Triple::sparcv9: 352 case llvm::Triple::systemz: 353 arch_64.SetTriple(triple); 354 break; 355 } 356 } 357