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/Support/Path.h" 22 #include "llvm/Support/ScopedPrinter.h" 23 #include "llvm/Support/Threading.h" 24 #include "llvm/Support/raw_ostream.h" 25 #include "llvm/TargetParser/Host.h" 26 #include "llvm/TargetParser/Triple.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 LogChannelSystem::Initialize(); 80 } 81 82 void HostInfoBase::Terminate() { 83 LogChannelSystem::Terminate(); 84 g_shlib_dir_helper = nullptr; 85 delete g_fields; 86 g_fields = nullptr; 87 } 88 89 llvm::Triple HostInfoBase::GetTargetTriple() { 90 llvm::call_once(g_fields->m_host_triple_once, []() { 91 g_fields->m_host_triple = HostInfo::GetArchitecture().GetTriple(); 92 }); 93 return g_fields->m_host_triple; 94 } 95 96 const ArchSpec &HostInfoBase::GetArchitecture(ArchitectureKind arch_kind) { 97 llvm::call_once(g_fields->m_host_arch_once, []() { 98 HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32, 99 g_fields->m_host_arch_64); 100 }); 101 102 // If an explicit 32 or 64-bit architecture was requested, return that. 103 if (arch_kind == eArchKind32) 104 return g_fields->m_host_arch_32; 105 if (arch_kind == eArchKind64) 106 return g_fields->m_host_arch_64; 107 108 // Otherwise prefer the 64-bit architecture if it is valid. 109 return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64 110 : g_fields->m_host_arch_32; 111 } 112 113 std::optional<HostInfoBase::ArchitectureKind> 114 HostInfoBase::ParseArchitectureKind(llvm::StringRef kind) { 115 return llvm::StringSwitch<std::optional<ArchitectureKind>>(kind) 116 .Case(LLDB_ARCH_DEFAULT, eArchKindDefault) 117 .Case(LLDB_ARCH_DEFAULT_32BIT, eArchKind32) 118 .Case(LLDB_ARCH_DEFAULT_64BIT, eArchKind64) 119 .Default(std::nullopt); 120 } 121 122 FileSpec HostInfoBase::GetShlibDir() { 123 llvm::call_once(g_fields->m_lldb_so_dir_once, []() { 124 if (!HostInfo::ComputeSharedLibraryDirectory(g_fields->m_lldb_so_dir)) 125 g_fields->m_lldb_so_dir = FileSpec(); 126 Log *log = GetLog(LLDBLog::Host); 127 LLDB_LOG(log, "shlib dir -> `{0}`", g_fields->m_lldb_so_dir); 128 }); 129 return g_fields->m_lldb_so_dir; 130 } 131 132 FileSpec HostInfoBase::GetSupportExeDir() { 133 llvm::call_once(g_fields->m_lldb_support_exe_dir_once, []() { 134 if (!HostInfo::ComputeSupportExeDirectory(g_fields->m_lldb_support_exe_dir)) 135 g_fields->m_lldb_support_exe_dir = FileSpec(); 136 Log *log = GetLog(LLDBLog::Host); 137 LLDB_LOG(log, "support exe dir -> `{0}`", g_fields->m_lldb_support_exe_dir); 138 }); 139 return g_fields->m_lldb_support_exe_dir; 140 } 141 142 FileSpec HostInfoBase::GetHeaderDir() { 143 llvm::call_once(g_fields->m_lldb_headers_dir_once, []() { 144 if (!HostInfo::ComputeHeaderDirectory(g_fields->m_lldb_headers_dir)) 145 g_fields->m_lldb_headers_dir = FileSpec(); 146 Log *log = GetLog(LLDBLog::Host); 147 LLDB_LOG(log, "header dir -> `{0}`", g_fields->m_lldb_headers_dir); 148 }); 149 return g_fields->m_lldb_headers_dir; 150 } 151 152 FileSpec HostInfoBase::GetSystemPluginDir() { 153 llvm::call_once(g_fields->m_lldb_system_plugin_dir_once, []() { 154 if (!HostInfo::ComputeSystemPluginsDirectory( 155 g_fields->m_lldb_system_plugin_dir)) 156 g_fields->m_lldb_system_plugin_dir = FileSpec(); 157 Log *log = GetLog(LLDBLog::Host); 158 LLDB_LOG(log, "system plugin dir -> `{0}`", 159 g_fields->m_lldb_system_plugin_dir); 160 }); 161 return g_fields->m_lldb_system_plugin_dir; 162 } 163 164 FileSpec HostInfoBase::GetUserPluginDir() { 165 llvm::call_once(g_fields->m_lldb_user_plugin_dir_once, []() { 166 if (!HostInfo::ComputeUserPluginsDirectory( 167 g_fields->m_lldb_user_plugin_dir)) 168 g_fields->m_lldb_user_plugin_dir = FileSpec(); 169 Log *log = GetLog(LLDBLog::Host); 170 LLDB_LOG(log, "user plugin dir -> `{0}`", g_fields->m_lldb_user_plugin_dir); 171 }); 172 return g_fields->m_lldb_user_plugin_dir; 173 } 174 175 FileSpec HostInfoBase::GetProcessTempDir() { 176 llvm::call_once(g_fields->m_lldb_process_tmp_dir_once, []() { 177 if (!HostInfo::ComputeProcessTempFileDirectory( 178 g_fields->m_lldb_process_tmp_dir)) 179 g_fields->m_lldb_process_tmp_dir = FileSpec(); 180 Log *log = GetLog(LLDBLog::Host); 181 LLDB_LOG(log, "process temp dir -> `{0}`", 182 g_fields->m_lldb_process_tmp_dir); 183 }); 184 return g_fields->m_lldb_process_tmp_dir; 185 } 186 187 FileSpec HostInfoBase::GetGlobalTempDir() { 188 llvm::call_once(g_fields->m_lldb_global_tmp_dir_once, []() { 189 if (!HostInfo::ComputeGlobalTempFileDirectory( 190 g_fields->m_lldb_global_tmp_dir)) 191 g_fields->m_lldb_global_tmp_dir = FileSpec(); 192 193 Log *log = GetLog(LLDBLog::Host); 194 LLDB_LOG(log, "global temp dir -> `{0}`", g_fields->m_lldb_global_tmp_dir); 195 }); 196 return g_fields->m_lldb_global_tmp_dir; 197 } 198 199 ArchSpec HostInfoBase::GetAugmentedArchSpec(llvm::StringRef triple) { 200 if (triple.empty()) 201 return ArchSpec(); 202 llvm::Triple normalized_triple(llvm::Triple::normalize(triple)); 203 if (!ArchSpec::ContainsOnlyArch(normalized_triple)) 204 return ArchSpec(triple); 205 206 if (auto kind = HostInfo::ParseArchitectureKind(triple)) 207 return HostInfo::GetArchitecture(*kind); 208 209 llvm::Triple host_triple(llvm::sys::getDefaultTargetTriple()); 210 211 if (normalized_triple.getVendorName().empty()) 212 normalized_triple.setVendor(host_triple.getVendor()); 213 if (normalized_triple.getOSName().empty()) 214 normalized_triple.setOS(host_triple.getOS()); 215 if (normalized_triple.getEnvironmentName().empty() && 216 !host_triple.getEnvironmentName().empty()) 217 normalized_triple.setEnvironment(host_triple.getEnvironment()); 218 return ArchSpec(normalized_triple); 219 } 220 221 bool HostInfoBase::ComputePathRelativeToLibrary(FileSpec &file_spec, 222 llvm::StringRef dir) { 223 Log *log = GetLog(LLDBLog::Host); 224 225 FileSpec lldb_file_spec = GetShlibDir(); 226 if (!lldb_file_spec) 227 return false; 228 229 std::string raw_path = lldb_file_spec.GetPath(); 230 LLDB_LOG( 231 log, 232 "Attempting to derive the path {0} relative to liblldb install path: {1}", 233 dir, raw_path); 234 235 // Drop bin (windows) or lib 236 llvm::StringRef parent_path = llvm::sys::path::parent_path(raw_path); 237 if (parent_path.empty()) { 238 LLDB_LOG(log, "Failed to find liblldb within the shared lib path"); 239 return false; 240 } 241 242 raw_path = (parent_path + dir).str(); 243 LLDB_LOG(log, "Derived the path as: {0}", raw_path); 244 file_spec.SetDirectory(raw_path); 245 return (bool)file_spec.GetDirectory(); 246 } 247 248 bool HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec) { 249 // To get paths related to LLDB we get the path to the executable that 250 // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB". 251 // On other posix systems, we will get .../lib(64|32)?/liblldb.so. 252 253 FileSpec lldb_file_spec(Host::GetModuleFileSpecForHostAddress( 254 reinterpret_cast<void *>(HostInfoBase::ComputeSharedLibraryDirectory))); 255 256 if (g_shlib_dir_helper) 257 g_shlib_dir_helper(lldb_file_spec); 258 259 // Remove the filename so that this FileSpec only represents the directory. 260 file_spec.SetDirectory(lldb_file_spec.GetDirectory()); 261 262 return (bool)file_spec.GetDirectory(); 263 } 264 265 bool HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) { 266 file_spec = GetShlibDir(); 267 return bool(file_spec); 268 } 269 270 bool HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec) { 271 FileSpec temp_file_spec; 272 if (!HostInfo::ComputeGlobalTempFileDirectory(temp_file_spec)) 273 return false; 274 275 std::string pid_str{llvm::to_string(Host::GetCurrentProcessID())}; 276 temp_file_spec.AppendPathComponent(pid_str); 277 if (llvm::sys::fs::create_directory(temp_file_spec.GetPath())) 278 return false; 279 280 file_spec.SetDirectory(temp_file_spec.GetPathAsConstString()); 281 return true; 282 } 283 284 bool HostInfoBase::ComputeTempFileBaseDirectory(FileSpec &file_spec) { 285 llvm::SmallVector<char, 16> tmpdir; 286 llvm::sys::path::system_temp_directory(/*ErasedOnReboot*/ true, tmpdir); 287 file_spec = FileSpec(std::string(tmpdir.data(), tmpdir.size())); 288 FileSystem::Instance().Resolve(file_spec); 289 return true; 290 } 291 292 bool HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) { 293 file_spec.Clear(); 294 295 FileSpec temp_file_spec; 296 if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec)) 297 return false; 298 299 temp_file_spec.AppendPathComponent("lldb"); 300 if (llvm::sys::fs::create_directory(temp_file_spec.GetPath())) 301 return false; 302 303 file_spec.SetDirectory(temp_file_spec.GetPathAsConstString()); 304 return true; 305 } 306 307 bool HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec) { 308 // TODO(zturner): Figure out how to compute the header directory for all 309 // platforms. 310 return false; 311 } 312 313 bool HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec) { 314 // TODO(zturner): Figure out how to compute the system plugins directory for 315 // all platforms. 316 return false; 317 } 318 319 bool HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) { 320 // TODO(zturner): Figure out how to compute the user plugins directory for 321 // all platforms. 322 return false; 323 } 324 325 void HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, 326 ArchSpec &arch_64) { 327 llvm::Triple triple(llvm::sys::getProcessTriple()); 328 329 arch_32.Clear(); 330 arch_64.Clear(); 331 332 switch (triple.getArch()) { 333 default: 334 arch_32.SetTriple(triple); 335 break; 336 337 case llvm::Triple::aarch64: 338 case llvm::Triple::ppc64: 339 case llvm::Triple::ppc64le: 340 case llvm::Triple::x86_64: 341 case llvm::Triple::riscv64: 342 case llvm::Triple::loongarch64: 343 arch_64.SetTriple(triple); 344 arch_32.SetTriple(triple.get32BitArchVariant()); 345 break; 346 347 case llvm::Triple::mips64: 348 case llvm::Triple::mips64el: 349 case llvm::Triple::sparcv9: 350 case llvm::Triple::systemz: 351 arch_64.SetTriple(triple); 352 break; 353 } 354 } 355