HostInfoBase.cpp revision 360660
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 30using namespace lldb; 31using namespace lldb_private; 32 33namespace { 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 40struct 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 65HostInfoBaseFields *g_fields = nullptr; 66} 67 68void HostInfoBase::Initialize() { g_fields = new HostInfoBaseFields(); } 69 70void HostInfoBase::Terminate() { 71 delete g_fields; 72 g_fields = nullptr; 73} 74 75llvm::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 84const 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 102llvm::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 110FileSpec 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 121FileSpec 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 133FileSpec 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 144FileSpec 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 157FileSpec 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 169FileSpec 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 182FileSpec 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 194ArchSpec 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 215bool 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 if (log) 225 log->Printf("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 if (log) 233 log->Printf("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 if (log) 241 log->Printf("HostInfo::%s() derived the path as: %s", __FUNCTION__, 242 raw_path.c_str()); 243 file_spec.GetDirectory().SetString(raw_path); 244 return (bool)file_spec.GetDirectory(); 245} 246 247bool HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec) { 248 // To get paths related to LLDB we get the path to the executable that 249 // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB". 250 // On other posix systems, we will get .../lib(64|32)?/liblldb.so. 251 252 FileSpec lldb_file_spec(Host::GetModuleFileSpecForHostAddress( 253 reinterpret_cast<void *>(reinterpret_cast<intptr_t>( 254 HostInfoBase::ComputeSharedLibraryDirectory)))); 255 256 // This is necessary because when running the testsuite the shlib might be a 257 // symbolic link inside the Python resource dir. 258 FileSystem::Instance().ResolveSymbolicLink(lldb_file_spec, 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 266bool HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) { 267 file_spec = GetShlibDir(); 268 return bool(file_spec); 269} 270 271bool 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 285bool 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 293bool 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 308bool 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 314bool 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 320bool 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 326void 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