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