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/Log.h" 17 #include "lldb/Utility/StreamString.h" 18 19 #include "llvm/ADT/StringExtras.h" 20 #include "llvm/ADT/Triple.h" 21 #include "llvm/Support/Host.h" 22 #include "llvm/Support/Path.h" 23 #include "llvm/Support/ScopedPrinter.h" 24 #include "llvm/Support/Threading.h" 25 #include "llvm/Support/raw_ostream.h" 26 27 #include <mutex> 28 #include <thread> 29 30 using namespace lldb; 31 using namespace lldb_private; 32 33 namespace { 34 // The HostInfoBaseFields is a work around for windows not supporting static 35 // variables correctly in a thread safe way. Really each of the variables in 36 // HostInfoBaseFields should live in the functions in which they are used and 37 // each one should be static, but the work around is in place to avoid this 38 // restriction. Ick. 39 40 struct HostInfoBaseFields { 41 ~HostInfoBaseFields() { 42 if (FileSystem::Instance().Exists(m_lldb_process_tmp_dir)) { 43 // Remove the LLDB temporary directory if we have one. Set "recurse" to 44 // true to all files that were created for the LLDB process can be 45 // cleaned up. 46 llvm::sys::fs::remove_directories(m_lldb_process_tmp_dir.GetPath()); 47 } 48 } 49 50 llvm::once_flag m_host_triple_once; 51 llvm::Triple m_host_triple; 52 53 llvm::once_flag m_host_arch_once; 54 ArchSpec m_host_arch_32; 55 ArchSpec m_host_arch_64; 56 57 llvm::once_flag m_lldb_so_dir_once; 58 FileSpec m_lldb_so_dir; 59 llvm::once_flag m_lldb_support_exe_dir_once; 60 FileSpec m_lldb_support_exe_dir; 61 llvm::once_flag m_lldb_headers_dir_once; 62 FileSpec m_lldb_headers_dir; 63 llvm::once_flag m_lldb_clang_resource_dir_once; 64 FileSpec m_lldb_clang_resource_dir; 65 llvm::once_flag m_lldb_system_plugin_dir_once; 66 FileSpec m_lldb_system_plugin_dir; 67 llvm::once_flag m_lldb_user_plugin_dir_once; 68 FileSpec m_lldb_user_plugin_dir; 69 llvm::once_flag m_lldb_process_tmp_dir_once; 70 FileSpec m_lldb_process_tmp_dir; 71 llvm::once_flag m_lldb_global_tmp_dir_once; 72 FileSpec m_lldb_global_tmp_dir; 73 }; 74 } // namespace 75 76 static HostInfoBaseFields *g_fields = nullptr; 77 static HostInfoBase::SharedLibraryDirectoryHelper *g_shlib_dir_helper = nullptr; 78 79 void HostInfoBase::Initialize(SharedLibraryDirectoryHelper *helper) { 80 g_shlib_dir_helper = helper; 81 g_fields = new HostInfoBaseFields(); 82 } 83 84 void HostInfoBase::Terminate() { 85 g_shlib_dir_helper = nullptr; 86 delete g_fields; 87 g_fields = nullptr; 88 } 89 90 llvm::Triple HostInfoBase::GetTargetTriple() { 91 llvm::call_once(g_fields->m_host_triple_once, []() { 92 g_fields->m_host_triple = 93 HostInfo::GetArchitecture().GetTriple(); 94 }); 95 return g_fields->m_host_triple; 96 } 97 98 const ArchSpec &HostInfoBase::GetArchitecture(ArchitectureKind arch_kind) { 99 llvm::call_once(g_fields->m_host_arch_once, []() { 100 HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32, 101 g_fields->m_host_arch_64); 102 }); 103 104 // If an explicit 32 or 64-bit architecture was requested, return that. 105 if (arch_kind == eArchKind32) 106 return g_fields->m_host_arch_32; 107 if (arch_kind == eArchKind64) 108 return g_fields->m_host_arch_64; 109 110 // Otherwise prefer the 64-bit architecture if it is valid. 111 return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64 112 : g_fields->m_host_arch_32; 113 } 114 115 llvm::Optional<HostInfoBase::ArchitectureKind> HostInfoBase::ParseArchitectureKind(llvm::StringRef kind) { 116 return llvm::StringSwitch<llvm::Optional<ArchitectureKind>>(kind) 117 .Case(LLDB_ARCH_DEFAULT, eArchKindDefault) 118 .Case(LLDB_ARCH_DEFAULT_32BIT, eArchKind32) 119 .Case(LLDB_ARCH_DEFAULT_64BIT, eArchKind64) 120 .Default(llvm::None); 121 } 122 123 FileSpec HostInfoBase::GetShlibDir() { 124 llvm::call_once(g_fields->m_lldb_so_dir_once, []() { 125 if (!HostInfo::ComputeSharedLibraryDirectory(g_fields->m_lldb_so_dir)) 126 g_fields->m_lldb_so_dir = FileSpec(); 127 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 128 LLDB_LOG(log, "shlib dir -> `{0}`", g_fields->m_lldb_so_dir); 129 }); 130 return g_fields->m_lldb_so_dir; 131 } 132 133 FileSpec HostInfoBase::GetSupportExeDir() { 134 llvm::call_once(g_fields->m_lldb_support_exe_dir_once, []() { 135 if (!HostInfo::ComputeSupportExeDirectory(g_fields->m_lldb_support_exe_dir)) 136 g_fields->m_lldb_support_exe_dir = FileSpec(); 137 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 138 LLDB_LOG(log, "support exe dir -> `{0}`", g_fields->m_lldb_support_exe_dir); 139 }); 140 return g_fields->m_lldb_support_exe_dir; 141 } 142 143 FileSpec HostInfoBase::GetHeaderDir() { 144 llvm::call_once(g_fields->m_lldb_headers_dir_once, []() { 145 if (!HostInfo::ComputeHeaderDirectory(g_fields->m_lldb_headers_dir)) 146 g_fields->m_lldb_headers_dir = FileSpec(); 147 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 148 LLDB_LOG(log, "header dir -> `{0}`", g_fields->m_lldb_headers_dir); 149 }); 150 return g_fields->m_lldb_headers_dir; 151 } 152 153 FileSpec HostInfoBase::GetSystemPluginDir() { 154 llvm::call_once(g_fields->m_lldb_system_plugin_dir_once, []() { 155 if (!HostInfo::ComputeSystemPluginsDirectory(g_fields->m_lldb_system_plugin_dir)) 156 g_fields->m_lldb_system_plugin_dir = FileSpec(); 157 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_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(g_fields->m_lldb_user_plugin_dir)) 167 g_fields->m_lldb_user_plugin_dir = FileSpec(); 168 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 169 LLDB_LOG(log, "user plugin dir -> `{0}`", g_fields->m_lldb_user_plugin_dir); 170 }); 171 return g_fields->m_lldb_user_plugin_dir; 172 } 173 174 FileSpec HostInfoBase::GetProcessTempDir() { 175 llvm::call_once(g_fields->m_lldb_process_tmp_dir_once, []() { 176 if (!HostInfo::ComputeProcessTempFileDirectory( g_fields->m_lldb_process_tmp_dir)) 177 g_fields->m_lldb_process_tmp_dir = FileSpec(); 178 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_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( g_fields->m_lldb_global_tmp_dir)) 188 g_fields->m_lldb_global_tmp_dir = FileSpec(); 189 190 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 191 LLDB_LOG(log, "global temp dir -> `{0}`", g_fields->m_lldb_global_tmp_dir); 192 }); 193 return g_fields->m_lldb_global_tmp_dir; 194 } 195 196 ArchSpec HostInfoBase::GetAugmentedArchSpec(llvm::StringRef triple) { 197 if (triple.empty()) 198 return ArchSpec(); 199 llvm::Triple normalized_triple(llvm::Triple::normalize(triple)); 200 if (!ArchSpec::ContainsOnlyArch(normalized_triple)) 201 return ArchSpec(triple); 202 203 if (auto kind = HostInfo::ParseArchitectureKind(triple)) 204 return HostInfo::GetArchitecture(*kind); 205 206 llvm::Triple host_triple(llvm::sys::getDefaultTargetTriple()); 207 208 if (normalized_triple.getVendorName().empty()) 209 normalized_triple.setVendor(host_triple.getVendor()); 210 if (normalized_triple.getOSName().empty()) 211 normalized_triple.setOS(host_triple.getOS()); 212 if (normalized_triple.getEnvironmentName().empty()) 213 normalized_triple.setEnvironment(host_triple.getEnvironment()); 214 return ArchSpec(normalized_triple); 215 } 216 217 bool HostInfoBase::ComputePathRelativeToLibrary(FileSpec &file_spec, 218 llvm::StringRef dir) { 219 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 220 221 FileSpec lldb_file_spec = GetShlibDir(); 222 if (!lldb_file_spec) 223 return false; 224 225 std::string raw_path = lldb_file_spec.GetPath(); 226 LLDB_LOGF(log, 227 "HostInfo::%s() attempting to " 228 "derive the path %s relative to liblldb install path: %s", 229 __FUNCTION__, dir.data(), raw_path.c_str()); 230 231 // Drop bin (windows) or lib 232 llvm::StringRef parent_path = llvm::sys::path::parent_path(raw_path); 233 if (parent_path.empty()) { 234 LLDB_LOGF(log, 235 "HostInfo::%s() failed to find liblldb within the shared " 236 "lib path", 237 __FUNCTION__); 238 return false; 239 } 240 241 raw_path = (parent_path + dir).str(); 242 LLDB_LOGF(log, "HostInfo::%s() derived the path as: %s", __FUNCTION__, 243 raw_path.c_str()); 244 file_spec.GetDirectory().SetString(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 *>( 255 HostInfoBase::ComputeSharedLibraryDirectory))); 256 257 if (g_shlib_dir_helper) 258 g_shlib_dir_helper(lldb_file_spec); 259 260 // Remove the filename so that this FileSpec only represents the directory. 261 file_spec.GetDirectory() = lldb_file_spec.GetDirectory(); 262 263 return (bool)file_spec.GetDirectory(); 264 } 265 266 bool HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) { 267 file_spec = GetShlibDir(); 268 return bool(file_spec); 269 } 270 271 bool HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec) { 272 FileSpec temp_file_spec; 273 if (!HostInfo::ComputeGlobalTempFileDirectory(temp_file_spec)) 274 return false; 275 276 std::string pid_str{llvm::to_string(Host::GetCurrentProcessID())}; 277 temp_file_spec.AppendPathComponent(pid_str); 278 if (llvm::sys::fs::create_directory(temp_file_spec.GetPath())) 279 return false; 280 281 file_spec.GetDirectory().SetCString(temp_file_spec.GetCString()); 282 return true; 283 } 284 285 bool HostInfoBase::ComputeTempFileBaseDirectory(FileSpec &file_spec) { 286 llvm::SmallVector<char, 16> tmpdir; 287 llvm::sys::path::system_temp_directory(/*ErasedOnReboot*/ true, tmpdir); 288 file_spec = FileSpec(std::string(tmpdir.data(), tmpdir.size())); 289 FileSystem::Instance().Resolve(file_spec); 290 return true; 291 } 292 293 bool HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) { 294 file_spec.Clear(); 295 296 FileSpec temp_file_spec; 297 if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec)) 298 return false; 299 300 temp_file_spec.AppendPathComponent("lldb"); 301 if (llvm::sys::fs::create_directory(temp_file_spec.GetPath())) 302 return false; 303 304 file_spec.GetDirectory().SetCString(temp_file_spec.GetCString()); 305 return true; 306 } 307 308 bool HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec) { 309 // TODO(zturner): Figure out how to compute the header directory for all 310 // platforms. 311 return false; 312 } 313 314 bool HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec) { 315 // TODO(zturner): Figure out how to compute the system plugins directory for 316 // all platforms. 317 return false; 318 } 319 320 bool HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) { 321 // TODO(zturner): Figure out how to compute the user plugins directory for 322 // all platforms. 323 return false; 324 } 325 326 void HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, 327 ArchSpec &arch_64) { 328 llvm::Triple triple(llvm::sys::getProcessTriple()); 329 330 arch_32.Clear(); 331 arch_64.Clear(); 332 333 switch (triple.getArch()) { 334 default: 335 arch_32.SetTriple(triple); 336 break; 337 338 case llvm::Triple::aarch64: 339 case llvm::Triple::ppc64: 340 case llvm::Triple::ppc64le: 341 case llvm::Triple::x86_64: 342 arch_64.SetTriple(triple); 343 arch_32.SetTriple(triple.get32BitArchVariant()); 344 break; 345 346 case llvm::Triple::mips64: 347 case llvm::Triple::mips64el: 348 case llvm::Triple::sparcv9: 349 case llvm::Triple::systemz: 350 arch_64.SetTriple(triple); 351 break; 352 } 353 } 354