HostInfoBase.cpp revision 355940
1110285Snyan//===-- HostInfoBase.cpp ----------------------------------------*- C++ -*-===// 2110285Snyan// 3110329Stakawata// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4110333Snyan// See https://llvm.org/LICENSE.txt for license information. 5110285Snyan// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6110285Snyan// 7110285Snyan//===----------------------------------------------------------------------===// 8110285Snyan 9110285Snyan#include "lldb/Host/Config.h" 10110285Snyan 11110285Snyan#include "lldb/Host/FileSystem.h" 12110285Snyan#include "lldb/Host/Host.h" 13110285Snyan#include "lldb/Host/HostInfo.h" 14110285Snyan#include "lldb/Host/HostInfoBase.h" 15110285Snyan#include "lldb/Utility/ArchSpec.h" 16110285Snyan#include "lldb/Utility/Log.h" 17110285Snyan#include "lldb/Utility/StreamString.h" 18110285Snyan 19110285Snyan#include "llvm/ADT/StringExtras.h" 20110285Snyan#include "llvm/ADT/Triple.h" 21110285Snyan#include "llvm/Support/Host.h" 22110285Snyan#include "llvm/Support/Path.h" 23110285Snyan#include "llvm/Support/ScopedPrinter.h" 24110285Snyan#include "llvm/Support/Threading.h" 25110333Snyan#include "llvm/Support/raw_ostream.h" 26110285Snyan 27110285Snyan#include <mutex> 28110285Snyan#include <thread> 29110285Snyan 30110285Snyanusing namespace lldb; 31110285Snyanusing namespace lldb_private; 32110285Snyan 33110285Snyannamespace { 34110285Snyan// The HostInfoBaseFields is a work around for windows not supporting static 35110285Snyan// variables correctly in a thread safe way. Really each of the variables in 36110285Snyan// HostInfoBaseFields should live in the functions in which they are used and 37110285Snyan// each one should be static, but the work around is in place to avoid this 38110285Snyan// restriction. Ick. 39110285Snyan 40110285Snyanstruct HostInfoBaseFields { 41110285Snyan ~HostInfoBaseFields() { 42110285Snyan if (FileSystem::Instance().Exists(m_lldb_process_tmp_dir)) { 43110285Snyan // Remove the LLDB temporary directory if we have one. Set "recurse" to 44110285Snyan // true to all files that were created for the LLDB process can be 45110285Snyan // cleaned up. 46110285Snyan llvm::sys::fs::remove_directories(m_lldb_process_tmp_dir.GetPath()); 47110285Snyan } 48110285Snyan } 49110285Snyan 50110285Snyan std::string m_host_triple; 51110285Snyan 52110285Snyan ArchSpec m_host_arch_32; 53110285Snyan ArchSpec m_host_arch_64; 54110285Snyan 55110285Snyan FileSpec m_lldb_so_dir; 56110285Snyan FileSpec m_lldb_support_exe_dir; 57110285Snyan FileSpec m_lldb_headers_dir; 58110285Snyan FileSpec m_lldb_clang_resource_dir; 59110285Snyan FileSpec m_lldb_system_plugin_dir; 60110285Snyan FileSpec m_lldb_user_plugin_dir; 61110285Snyan FileSpec m_lldb_process_tmp_dir; 62110285Snyan FileSpec m_lldb_global_tmp_dir; 63110285Snyan}; 64110285Snyan 65110285SnyanHostInfoBaseFields *g_fields = nullptr; 66110285Snyan} 67110285Snyan 68110285Snyanvoid HostInfoBase::Initialize() { g_fields = new HostInfoBaseFields(); } 69110285Snyan 70110285Snyanvoid HostInfoBase::Terminate() { 71110285Snyan delete g_fields; 72110285Snyan g_fields = nullptr; 73110285Snyan} 74110285Snyan 75110285Snyanllvm::StringRef HostInfoBase::GetTargetTriple() { 76110285Snyan static llvm::once_flag g_once_flag; 77110285Snyan llvm::call_once(g_once_flag, []() { 78110285Snyan g_fields->m_host_triple = 79110285Snyan HostInfo::GetArchitecture().GetTriple().getTriple(); 80110285Snyan }); 81110285Snyan return g_fields->m_host_triple; 82110285Snyan} 83110285Snyan 84110285Snyanconst ArchSpec &HostInfoBase::GetArchitecture(ArchitectureKind arch_kind) { 85110285Snyan static llvm::once_flag g_once_flag; 86110285Snyan llvm::call_once(g_once_flag, []() { 87110285Snyan HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32, 88110285Snyan g_fields->m_host_arch_64); 89110285Snyan }); 90110285Snyan 91110285Snyan // If an explicit 32 or 64-bit architecture was requested, return that. 92110285Snyan if (arch_kind == eArchKind32) 93110285Snyan return g_fields->m_host_arch_32; 94110285Snyan if (arch_kind == eArchKind64) 95110285Snyan return g_fields->m_host_arch_64; 96110285Snyan 97110285Snyan // Otherwise prefer the 64-bit architecture if it is valid. 98110285Snyan return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64 99110285Snyan : g_fields->m_host_arch_32; 100110285Snyan} 101110285Snyan 102110285Snyanllvm::Optional<HostInfoBase::ArchitectureKind> HostInfoBase::ParseArchitectureKind(llvm::StringRef kind) { 103110285Snyan return llvm::StringSwitch<llvm::Optional<ArchitectureKind>>(kind) 104110285Snyan .Case(LLDB_ARCH_DEFAULT, eArchKindDefault) 105110285Snyan .Case(LLDB_ARCH_DEFAULT_32BIT, eArchKind32) 106110285Snyan .Case(LLDB_ARCH_DEFAULT_64BIT, eArchKind64) 107110285Snyan .Default(llvm::None); 108110285Snyan} 109110285Snyan 110110285SnyanFileSpec 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