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