1 //===-- HostInfoBase.cpp ----------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "lldb/Host/Config.h" 11 12 #include "lldb/Host/FileSystem.h" 13 #include "lldb/Host/Host.h" 14 #include "lldb/Host/HostInfo.h" 15 #include "lldb/Host/HostInfoBase.h" 16 #include "lldb/Utility/ArchSpec.h" 17 #include "lldb/Utility/Log.h" 18 #include "lldb/Utility/StreamString.h" 19 20 #include "llvm/ADT/StringExtras.h" 21 #include "llvm/ADT/Triple.h" 22 #include "llvm/Support/Host.h" 23 #include "llvm/Support/Path.h" 24 #include "llvm/Support/ScopedPrinter.h" 25 #include "llvm/Support/Threading.h" 26 #include "llvm/Support/raw_ostream.h" 27 28 #include <mutex> 29 #include <thread> 30 31 using namespace lldb; 32 using namespace lldb_private; 33 34 namespace { 35 //---------------------------------------------------------------------- 36 // The HostInfoBaseFields is a work around for windows not supporting static 37 // variables correctly in a thread safe way. Really each of the variables in 38 // HostInfoBaseFields should live in the functions in which they are used and 39 // each one should be static, but the work around is in place to avoid this 40 // restriction. Ick. 41 //---------------------------------------------------------------------- 42 43 struct HostInfoBaseFields { 44 ~HostInfoBaseFields() { 45 if (FileSystem::Instance().Exists(m_lldb_process_tmp_dir)) { 46 // Remove the LLDB temporary directory if we have one. Set "recurse" to 47 // true to all files that were created for the LLDB process can be 48 // cleaned up. 49 llvm::sys::fs::remove_directories(m_lldb_process_tmp_dir.GetPath()); 50 } 51 } 52 53 std::string m_host_triple; 54 55 ArchSpec m_host_arch_32; 56 ArchSpec m_host_arch_64; 57 58 FileSpec m_lldb_so_dir; 59 FileSpec m_lldb_support_exe_dir; 60 FileSpec m_lldb_headers_dir; 61 FileSpec m_lldb_clang_resource_dir; 62 FileSpec m_lldb_system_plugin_dir; 63 FileSpec m_lldb_user_plugin_dir; 64 FileSpec m_lldb_process_tmp_dir; 65 FileSpec m_lldb_global_tmp_dir; 66 }; 67 68 HostInfoBaseFields *g_fields = nullptr; 69 } 70 71 void HostInfoBase::Initialize() { g_fields = new HostInfoBaseFields(); } 72 73 void HostInfoBase::Terminate() { 74 delete g_fields; 75 g_fields = nullptr; 76 } 77 78 llvm::StringRef HostInfoBase::GetTargetTriple() { 79 static llvm::once_flag g_once_flag; 80 llvm::call_once(g_once_flag, []() { 81 g_fields->m_host_triple = 82 HostInfo::GetArchitecture().GetTriple().getTriple(); 83 }); 84 return g_fields->m_host_triple; 85 } 86 87 const ArchSpec &HostInfoBase::GetArchitecture(ArchitectureKind arch_kind) { 88 static llvm::once_flag g_once_flag; 89 llvm::call_once(g_once_flag, []() { 90 HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32, 91 g_fields->m_host_arch_64); 92 }); 93 94 // If an explicit 32 or 64-bit architecture was requested, return that. 95 if (arch_kind == eArchKind32) 96 return g_fields->m_host_arch_32; 97 if (arch_kind == eArchKind64) 98 return g_fields->m_host_arch_64; 99 100 // Otherwise prefer the 64-bit architecture if it is valid. 101 return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64 102 : g_fields->m_host_arch_32; 103 } 104 105 llvm::Optional<HostInfoBase::ArchitectureKind> HostInfoBase::ParseArchitectureKind(llvm::StringRef kind) { 106 return llvm::StringSwitch<llvm::Optional<ArchitectureKind>>(kind) 107 .Case(LLDB_ARCH_DEFAULT, eArchKindDefault) 108 .Case(LLDB_ARCH_DEFAULT_32BIT, eArchKind32) 109 .Case(LLDB_ARCH_DEFAULT_64BIT, eArchKind64) 110 .Default(llvm::None); 111 } 112 113 FileSpec HostInfoBase::GetShlibDir() { 114 static llvm::once_flag g_once_flag; 115 static bool success = false; 116 llvm::call_once(g_once_flag, []() { 117 success = HostInfo::ComputeSharedLibraryDirectory(g_fields->m_lldb_so_dir); 118 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 119 LLDB_LOG(log, "shlib dir -> `{0}`", g_fields->m_lldb_so_dir); 120 }); 121 return success ? g_fields->m_lldb_so_dir : FileSpec(); 122 } 123 124 FileSpec HostInfoBase::GetSupportExeDir() { 125 static llvm::once_flag g_once_flag; 126 static bool success = false; 127 llvm::call_once(g_once_flag, []() { 128 success = 129 HostInfo::ComputeSupportExeDirectory(g_fields->m_lldb_support_exe_dir); 130 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 131 LLDB_LOG(log, "support exe dir -> `{0}`", g_fields->m_lldb_support_exe_dir); 132 }); 133 return success ? g_fields->m_lldb_support_exe_dir : FileSpec(); 134 } 135 136 FileSpec HostInfoBase::GetHeaderDir() { 137 static llvm::once_flag g_once_flag; 138 static bool success = false; 139 llvm::call_once(g_once_flag, []() { 140 success = HostInfo::ComputeHeaderDirectory(g_fields->m_lldb_headers_dir); 141 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 142 LLDB_LOG(log, "header dir -> `{0}`", g_fields->m_lldb_headers_dir); 143 }); 144 return success ? g_fields->m_lldb_headers_dir : FileSpec(); 145 } 146 147 FileSpec HostInfoBase::GetSystemPluginDir() { 148 static llvm::once_flag g_once_flag; 149 static bool success = false; 150 llvm::call_once(g_once_flag, []() { 151 success = HostInfo::ComputeSystemPluginsDirectory( 152 g_fields->m_lldb_system_plugin_dir); 153 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 154 LLDB_LOG(log, "system plugin dir -> `{0}`", 155 g_fields->m_lldb_system_plugin_dir); 156 }); 157 return success ? g_fields->m_lldb_system_plugin_dir : FileSpec(); 158 } 159 160 FileSpec HostInfoBase::GetUserPluginDir() { 161 static llvm::once_flag g_once_flag; 162 static bool success = false; 163 llvm::call_once(g_once_flag, []() { 164 success = 165 HostInfo::ComputeUserPluginsDirectory(g_fields->m_lldb_user_plugin_dir); 166 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 167 LLDB_LOG(log, "user plugin dir -> `{0}`", g_fields->m_lldb_user_plugin_dir); 168 }); 169 return success ? g_fields->m_lldb_user_plugin_dir : FileSpec(); 170 } 171 172 FileSpec HostInfoBase::GetProcessTempDir() { 173 static llvm::once_flag g_once_flag; 174 static bool success = false; 175 llvm::call_once(g_once_flag, []() { 176 success = HostInfo::ComputeProcessTempFileDirectory( 177 g_fields->m_lldb_process_tmp_dir); 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 success ? g_fields->m_lldb_process_tmp_dir : FileSpec(); 183 } 184 185 FileSpec HostInfoBase::GetGlobalTempDir() { 186 static llvm::once_flag g_once_flag; 187 static bool success = false; 188 llvm::call_once(g_once_flag, []() { 189 success = HostInfo::ComputeGlobalTempFileDirectory( 190 g_fields->m_lldb_global_tmp_dir); 191 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 192 LLDB_LOG(log, "global temp dir -> `{0}`", g_fields->m_lldb_global_tmp_dir); 193 }); 194 return success ? g_fields->m_lldb_global_tmp_dir : FileSpec(); 195 } 196 197 ArchSpec HostInfoBase::GetAugmentedArchSpec(llvm::StringRef triple) { 198 if (triple.empty()) 199 return ArchSpec(); 200 llvm::Triple normalized_triple(llvm::Triple::normalize(triple)); 201 if (!ArchSpec::ContainsOnlyArch(normalized_triple)) 202 return ArchSpec(triple); 203 204 if (auto kind = HostInfo::ParseArchitectureKind(triple)) 205 return HostInfo::GetArchitecture(*kind); 206 207 llvm::Triple host_triple(llvm::sys::getDefaultTargetTriple()); 208 209 if (normalized_triple.getVendorName().empty()) 210 normalized_triple.setVendor(host_triple.getVendor()); 211 if (normalized_triple.getOSName().empty()) 212 normalized_triple.setOS(host_triple.getOS()); 213 if (normalized_triple.getEnvironmentName().empty()) 214 normalized_triple.setEnvironment(host_triple.getEnvironment()); 215 return ArchSpec(normalized_triple); 216 } 217 218 bool HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec) { 219 // To get paths related to LLDB we get the path to the executable that 220 // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB". 221 // On other posix systems, we will get .../lib(64|32)?/liblldb.so. 222 223 FileSpec lldb_file_spec(Host::GetModuleFileSpecForHostAddress( 224 reinterpret_cast<void *>(reinterpret_cast<intptr_t>( 225 HostInfoBase::ComputeSharedLibraryDirectory)))); 226 227 // This is necessary because when running the testsuite the shlib might be a 228 // symbolic link inside the Python resource dir. 229 FileSystem::Instance().ResolveSymbolicLink(lldb_file_spec, lldb_file_spec); 230 231 // Remove the filename so that this FileSpec only represents the directory. 232 file_spec.GetDirectory() = lldb_file_spec.GetDirectory(); 233 234 return (bool)file_spec.GetDirectory(); 235 } 236 237 bool HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) { 238 file_spec = GetShlibDir(); 239 return bool(file_spec); 240 } 241 242 bool HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec) { 243 FileSpec temp_file_spec; 244 if (!HostInfo::ComputeGlobalTempFileDirectory(temp_file_spec)) 245 return false; 246 247 std::string pid_str{llvm::to_string(Host::GetCurrentProcessID())}; 248 temp_file_spec.AppendPathComponent(pid_str); 249 if (llvm::sys::fs::create_directory(temp_file_spec.GetPath())) 250 return false; 251 252 file_spec.GetDirectory().SetCString(temp_file_spec.GetCString()); 253 return true; 254 } 255 256 bool HostInfoBase::ComputeTempFileBaseDirectory(FileSpec &file_spec) { 257 llvm::SmallVector<char, 16> tmpdir; 258 llvm::sys::path::system_temp_directory(/*ErasedOnReboot*/ true, tmpdir); 259 file_spec = FileSpec(std::string(tmpdir.data(), tmpdir.size())); 260 FileSystem::Instance().Resolve(file_spec); 261 return true; 262 } 263 264 bool HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) { 265 file_spec.Clear(); 266 267 FileSpec temp_file_spec; 268 if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec)) 269 return false; 270 271 temp_file_spec.AppendPathComponent("lldb"); 272 if (llvm::sys::fs::create_directory(temp_file_spec.GetPath())) 273 return false; 274 275 file_spec.GetDirectory().SetCString(temp_file_spec.GetCString()); 276 return true; 277 } 278 279 bool HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec) { 280 // TODO(zturner): Figure out how to compute the header directory for all 281 // platforms. 282 return false; 283 } 284 285 bool HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec) { 286 // TODO(zturner): Figure out how to compute the system plugins directory for 287 // all platforms. 288 return false; 289 } 290 291 bool HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) { 292 // TODO(zturner): Figure out how to compute the user plugins directory for 293 // all platforms. 294 return false; 295 } 296 297 void HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, 298 ArchSpec &arch_64) { 299 llvm::Triple triple(llvm::sys::getProcessTriple()); 300 301 arch_32.Clear(); 302 arch_64.Clear(); 303 304 switch (triple.getArch()) { 305 default: 306 arch_32.SetTriple(triple); 307 break; 308 309 case llvm::Triple::aarch64: 310 case llvm::Triple::ppc64: 311 case llvm::Triple::ppc64le: 312 case llvm::Triple::x86_64: 313 arch_64.SetTriple(triple); 314 arch_32.SetTriple(triple.get32BitArchVariant()); 315 break; 316 317 case llvm::Triple::mips64: 318 case llvm::Triple::mips64el: 319 case llvm::Triple::sparcv9: 320 case llvm::Triple::systemz: 321 arch_64.SetTriple(triple); 322 break; 323 } 324 } 325