1 //===-- HostInfoBase.cpp ----------------------------------------*- C++ -*-===// 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 std::string m_host_triple; 51 52 ArchSpec m_host_arch_32; 53 ArchSpec m_host_arch_64; 54 55 FileSpec m_lldb_so_dir; 56 FileSpec m_lldb_support_exe_dir; 57 FileSpec m_lldb_headers_dir; 58 FileSpec m_lldb_clang_resource_dir; 59 FileSpec m_lldb_system_plugin_dir; 60 FileSpec m_lldb_user_plugin_dir; 61 FileSpec m_lldb_process_tmp_dir; 62 FileSpec m_lldb_global_tmp_dir; 63 }; 64 65 HostInfoBaseFields *g_fields = nullptr; 66 } 67 68 void HostInfoBase::Initialize() { g_fields = new HostInfoBaseFields(); } 69 70 void HostInfoBase::Terminate() { 71 delete g_fields; 72 g_fields = nullptr; 73 } 74 75 llvm::StringRef HostInfoBase::GetTargetTriple() { 76 static llvm::once_flag g_once_flag; 77 llvm::call_once(g_once_flag, []() { 78 g_fields->m_host_triple = 79 HostInfo::GetArchitecture().GetTriple().getTriple(); 80 }); 81 return g_fields->m_host_triple; 82 } 83 84 const ArchSpec &HostInfoBase::GetArchitecture(ArchitectureKind arch_kind) { 85 static llvm::once_flag g_once_flag; 86 llvm::call_once(g_once_flag, []() { 87 HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32, 88 g_fields->m_host_arch_64); 89 }); 90 91 // If an explicit 32 or 64-bit architecture was requested, return that. 92 if (arch_kind == eArchKind32) 93 return g_fields->m_host_arch_32; 94 if (arch_kind == eArchKind64) 95 return g_fields->m_host_arch_64; 96 97 // Otherwise prefer the 64-bit architecture if it is valid. 98 return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64 99 : g_fields->m_host_arch_32; 100 } 101 102 llvm::Optional<HostInfoBase::ArchitectureKind> HostInfoBase::ParseArchitectureKind(llvm::StringRef kind) { 103 return llvm::StringSwitch<llvm::Optional<ArchitectureKind>>(kind) 104 .Case(LLDB_ARCH_DEFAULT, eArchKindDefault) 105 .Case(LLDB_ARCH_DEFAULT_32BIT, eArchKind32) 106 .Case(LLDB_ARCH_DEFAULT_64BIT, eArchKind64) 107 .Default(llvm::None); 108 } 109 110 FileSpec HostInfoBase::GetShlibDir() { 111 static llvm::once_flag g_once_flag; 112 static bool success = false; 113 llvm::call_once(g_once_flag, []() { 114 success = HostInfo::ComputeSharedLibraryDirectory(g_fields->m_lldb_so_dir); 115 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 116 LLDB_LOG(log, "shlib dir -> `{0}`", g_fields->m_lldb_so_dir); 117 }); 118 return success ? g_fields->m_lldb_so_dir : FileSpec(); 119 } 120 121 FileSpec HostInfoBase::GetSupportExeDir() { 122 static llvm::once_flag g_once_flag; 123 static bool success = false; 124 llvm::call_once(g_once_flag, []() { 125 success = 126 HostInfo::ComputeSupportExeDirectory(g_fields->m_lldb_support_exe_dir); 127 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 128 LLDB_LOG(log, "support exe dir -> `{0}`", g_fields->m_lldb_support_exe_dir); 129 }); 130 return success ? g_fields->m_lldb_support_exe_dir : FileSpec(); 131 } 132 133 FileSpec HostInfoBase::GetHeaderDir() { 134 static llvm::once_flag g_once_flag; 135 static bool success = false; 136 llvm::call_once(g_once_flag, []() { 137 success = HostInfo::ComputeHeaderDirectory(g_fields->m_lldb_headers_dir); 138 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 139 LLDB_LOG(log, "header dir -> `{0}`", g_fields->m_lldb_headers_dir); 140 }); 141 return success ? g_fields->m_lldb_headers_dir : FileSpec(); 142 } 143 144 FileSpec HostInfoBase::GetSystemPluginDir() { 145 static llvm::once_flag g_once_flag; 146 static bool success = false; 147 llvm::call_once(g_once_flag, []() { 148 success = HostInfo::ComputeSystemPluginsDirectory( 149 g_fields->m_lldb_system_plugin_dir); 150 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 151 LLDB_LOG(log, "system plugin dir -> `{0}`", 152 g_fields->m_lldb_system_plugin_dir); 153 }); 154 return success ? g_fields->m_lldb_system_plugin_dir : FileSpec(); 155 } 156 157 FileSpec HostInfoBase::GetUserPluginDir() { 158 static llvm::once_flag g_once_flag; 159 static bool success = false; 160 llvm::call_once(g_once_flag, []() { 161 success = 162 HostInfo::ComputeUserPluginsDirectory(g_fields->m_lldb_user_plugin_dir); 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 success ? g_fields->m_lldb_user_plugin_dir : FileSpec(); 167 } 168 169 FileSpec HostInfoBase::GetProcessTempDir() { 170 static llvm::once_flag g_once_flag; 171 static bool success = false; 172 llvm::call_once(g_once_flag, []() { 173 success = HostInfo::ComputeProcessTempFileDirectory( 174 g_fields->m_lldb_process_tmp_dir); 175 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 176 LLDB_LOG(log, "process temp dir -> `{0}`", 177 g_fields->m_lldb_process_tmp_dir); 178 }); 179 return success ? g_fields->m_lldb_process_tmp_dir : FileSpec(); 180 } 181 182 FileSpec HostInfoBase::GetGlobalTempDir() { 183 static llvm::once_flag g_once_flag; 184 static bool success = false; 185 llvm::call_once(g_once_flag, []() { 186 success = HostInfo::ComputeGlobalTempFileDirectory( 187 g_fields->m_lldb_global_tmp_dir); 188 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 189 LLDB_LOG(log, "global temp dir -> `{0}`", g_fields->m_lldb_global_tmp_dir); 190 }); 191 return success ? g_fields->m_lldb_global_tmp_dir : FileSpec(); 192 } 193 194 ArchSpec HostInfoBase::GetAugmentedArchSpec(llvm::StringRef triple) { 195 if (triple.empty()) 196 return ArchSpec(); 197 llvm::Triple normalized_triple(llvm::Triple::normalize(triple)); 198 if (!ArchSpec::ContainsOnlyArch(normalized_triple)) 199 return ArchSpec(triple); 200 201 if (auto kind = HostInfo::ParseArchitectureKind(triple)) 202 return HostInfo::GetArchitecture(*kind); 203 204 llvm::Triple host_triple(llvm::sys::getDefaultTargetTriple()); 205 206 if (normalized_triple.getVendorName().empty()) 207 normalized_triple.setVendor(host_triple.getVendor()); 208 if (normalized_triple.getOSName().empty()) 209 normalized_triple.setOS(host_triple.getOS()); 210 if (normalized_triple.getEnvironmentName().empty()) 211 normalized_triple.setEnvironment(host_triple.getEnvironment()); 212 return ArchSpec(normalized_triple); 213 } 214 215 bool HostInfoBase::ComputePathRelativeToLibrary(FileSpec &file_spec, 216 llvm::StringRef dir) { 217 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 218 219 FileSpec lldb_file_spec = GetShlibDir(); 220 if (!lldb_file_spec) 221 return false; 222 223 std::string raw_path = lldb_file_spec.GetPath(); 224 LLDB_LOGF(log, 225 "HostInfo::%s() attempting to " 226 "derive the path %s relative to liblldb install path: %s", 227 __FUNCTION__, dir.data(), raw_path.c_str()); 228 229 // Drop bin (windows) or lib 230 llvm::StringRef parent_path = llvm::sys::path::parent_path(raw_path); 231 if (parent_path.empty()) { 232 LLDB_LOGF(log, 233 "HostInfo::%s() failed to find liblldb within the shared " 234 "lib path", 235 __FUNCTION__); 236 return false; 237 } 238 239 raw_path = (parent_path + dir).str(); 240 LLDB_LOGF(log, "HostInfo::%s() derived the path as: %s", __FUNCTION__, 241 raw_path.c_str()); 242 file_spec.GetDirectory().SetString(raw_path); 243 return (bool)file_spec.GetDirectory(); 244 } 245 246 bool HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec) { 247 // To get paths related to LLDB we get the path to the executable that 248 // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB". 249 // On other posix systems, we will get .../lib(64|32)?/liblldb.so. 250 251 FileSpec lldb_file_spec(Host::GetModuleFileSpecForHostAddress( 252 reinterpret_cast<void *>(reinterpret_cast<intptr_t>( 253 HostInfoBase::ComputeSharedLibraryDirectory)))); 254 255 // This is necessary because when running the testsuite the shlib might be a 256 // symbolic link inside the Python resource dir. 257 FileSystem::Instance().ResolveSymbolicLink(lldb_file_spec, lldb_file_spec); 258 259 // Remove the filename so that this FileSpec only represents the directory. 260 file_spec.GetDirectory() = 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.GetDirectory().SetCString(temp_file_spec.GetCString()); 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.GetDirectory().SetCString(temp_file_spec.GetCString()); 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 arch_64.SetTriple(triple); 342 arch_32.SetTriple(triple.get32BitArchVariant()); 343 break; 344 345 case llvm::Triple::mips64: 346 case llvm::Triple::mips64el: 347 case llvm::Triple::sparcv9: 348 case llvm::Triple::systemz: 349 arch_64.SetTriple(triple); 350 break; 351 } 352 } 353