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 (m_lldb_process_tmp_dir.Exists()) { 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_python_dir; 62 FileSpec m_lldb_clang_resource_dir; 63 FileSpec m_lldb_system_plugin_dir; 64 FileSpec m_lldb_user_plugin_dir; 65 FileSpec m_lldb_process_tmp_dir; 66 FileSpec m_lldb_global_tmp_dir; 67 }; 68 69 HostInfoBaseFields *g_fields = nullptr; 70 } 71 72 void HostInfoBase::Initialize() { g_fields = new HostInfoBaseFields(); } 73 74 void HostInfoBase::Terminate() { 75 delete g_fields; 76 g_fields = nullptr; 77 } 78 79 llvm::StringRef HostInfoBase::GetTargetTriple() { 80 static llvm::once_flag g_once_flag; 81 llvm::call_once(g_once_flag, []() { 82 g_fields->m_host_triple = 83 HostInfo::GetArchitecture().GetTriple().getTriple(); 84 }); 85 return g_fields->m_host_triple; 86 } 87 88 const ArchSpec &HostInfoBase::GetArchitecture(ArchitectureKind arch_kind) { 89 static llvm::once_flag g_once_flag; 90 llvm::call_once(g_once_flag, []() { 91 HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32, 92 g_fields->m_host_arch_64); 93 }); 94 95 // If an explicit 32 or 64-bit architecture was requested, return that. 96 if (arch_kind == eArchKind32) 97 return g_fields->m_host_arch_32; 98 if (arch_kind == eArchKind64) 99 return g_fields->m_host_arch_64; 100 101 // Otherwise prefer the 64-bit architecture if it is valid. 102 return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64 103 : g_fields->m_host_arch_32; 104 } 105 106 llvm::Optional<HostInfoBase::ArchitectureKind> HostInfoBase::ParseArchitectureKind(llvm::StringRef kind) { 107 return llvm::StringSwitch<llvm::Optional<ArchitectureKind>>(kind) 108 .Case(LLDB_ARCH_DEFAULT, eArchKindDefault) 109 .Case(LLDB_ARCH_DEFAULT_32BIT, eArchKind32) 110 .Case(LLDB_ARCH_DEFAULT_64BIT, eArchKind64) 111 .Default(llvm::None); 112 } 113 114 bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) { 115 file_spec.Clear(); 116 117 assert(type != lldb::ePathTypeClangDir); 118 119 #if defined(LLDB_DISABLE_PYTHON) 120 if (type == lldb::ePathTypePythonDir) 121 return false; 122 #endif 123 124 FileSpec *result = nullptr; 125 switch (type) { 126 case lldb::ePathTypeLLDBShlibDir: { 127 static llvm::once_flag g_once_flag; 128 static bool success = false; 129 llvm::call_once(g_once_flag, []() { 130 success = 131 HostInfo::ComputeSharedLibraryDirectory(g_fields->m_lldb_so_dir); 132 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 133 if (log) 134 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'", 135 g_fields->m_lldb_so_dir.GetPath().c_str()); 136 }); 137 if (success) 138 result = &g_fields->m_lldb_so_dir; 139 } break; 140 case lldb::ePathTypeSupportExecutableDir: { 141 static llvm::once_flag g_once_flag; 142 static bool success = false; 143 llvm::call_once(g_once_flag, []() { 144 success = HostInfo::ComputeSupportExeDirectory( 145 g_fields->m_lldb_support_exe_dir); 146 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 147 if (log) 148 log->Printf( 149 "HostInfoBase::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'", 150 g_fields->m_lldb_support_exe_dir.GetPath().c_str()); 151 }); 152 if (success) 153 result = &g_fields->m_lldb_support_exe_dir; 154 } break; 155 case lldb::ePathTypeHeaderDir: { 156 static llvm::once_flag g_once_flag; 157 static bool success = false; 158 llvm::call_once(g_once_flag, []() { 159 success = HostInfo::ComputeHeaderDirectory(g_fields->m_lldb_headers_dir); 160 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 161 if (log) 162 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeHeaderDir) => '%s'", 163 g_fields->m_lldb_headers_dir.GetPath().c_str()); 164 }); 165 if (success) 166 result = &g_fields->m_lldb_headers_dir; 167 } break; 168 case lldb::ePathTypePythonDir: { 169 static llvm::once_flag g_once_flag; 170 static bool success = false; 171 llvm::call_once(g_once_flag, []() { 172 success = HostInfo::ComputePythonDirectory(g_fields->m_lldb_python_dir); 173 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 174 if (log) 175 log->Printf("HostInfoBase::GetLLDBPath(ePathTypePythonDir) => '%s'", 176 g_fields->m_lldb_python_dir.GetPath().c_str()); 177 }); 178 if (success) 179 result = &g_fields->m_lldb_python_dir; 180 } break; 181 case lldb::ePathTypeLLDBSystemPlugins: { 182 static llvm::once_flag g_once_flag; 183 static bool success = false; 184 llvm::call_once(g_once_flag, []() { 185 success = HostInfo::ComputeSystemPluginsDirectory( 186 g_fields->m_lldb_system_plugin_dir); 187 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 188 if (log) 189 log->Printf( 190 "HostInfoBase::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'", 191 g_fields->m_lldb_system_plugin_dir.GetPath().c_str()); 192 }); 193 if (success) 194 result = &g_fields->m_lldb_system_plugin_dir; 195 } break; 196 case lldb::ePathTypeLLDBUserPlugins: { 197 static llvm::once_flag g_once_flag; 198 static bool success = false; 199 llvm::call_once(g_once_flag, []() { 200 success = HostInfo::ComputeUserPluginsDirectory( 201 g_fields->m_lldb_user_plugin_dir); 202 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 203 if (log) 204 log->Printf( 205 "HostInfoBase::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'", 206 g_fields->m_lldb_user_plugin_dir.GetPath().c_str()); 207 }); 208 if (success) 209 result = &g_fields->m_lldb_user_plugin_dir; 210 } break; 211 case lldb::ePathTypeLLDBTempSystemDir: { 212 static llvm::once_flag g_once_flag; 213 static bool success = false; 214 llvm::call_once(g_once_flag, []() { 215 success = HostInfo::ComputeProcessTempFileDirectory( 216 g_fields->m_lldb_process_tmp_dir); 217 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 218 if (log) 219 log->Printf( 220 "HostInfoBase::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", 221 g_fields->m_lldb_process_tmp_dir.GetPath().c_str()); 222 }); 223 if (success) 224 result = &g_fields->m_lldb_process_tmp_dir; 225 } break; 226 case lldb::ePathTypeGlobalLLDBTempSystemDir: { 227 static llvm::once_flag g_once_flag; 228 static bool success = false; 229 llvm::call_once(g_once_flag, []() { 230 success = HostInfo::ComputeGlobalTempFileDirectory( 231 g_fields->m_lldb_global_tmp_dir); 232 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 233 if (log) 234 log->Printf("HostInfoBase::GetLLDBPath(" 235 "ePathTypeGlobalLLDBTempSystemDir) => '%s'", 236 g_fields->m_lldb_global_tmp_dir.GetPath().c_str()); 237 }); 238 if (success) 239 result = &g_fields->m_lldb_global_tmp_dir; 240 } break; 241 default: 242 llvm_unreachable("Unreachable!"); 243 } 244 245 if (!result) 246 return false; 247 file_spec = *result; 248 return true; 249 } 250 251 ArchSpec HostInfoBase::GetAugmentedArchSpec(llvm::StringRef triple) { 252 if (triple.empty()) 253 return ArchSpec(); 254 llvm::Triple normalized_triple(llvm::Triple::normalize(triple)); 255 if (!ArchSpec::ContainsOnlyArch(normalized_triple)) 256 return ArchSpec(triple); 257 258 if (auto kind = HostInfo::ParseArchitectureKind(triple)) 259 return HostInfo::GetArchitecture(*kind); 260 261 llvm::Triple host_triple(llvm::sys::getDefaultTargetTriple()); 262 263 if (normalized_triple.getVendorName().empty()) 264 normalized_triple.setVendor(host_triple.getVendor()); 265 if (normalized_triple.getOSName().empty()) 266 normalized_triple.setOS(host_triple.getOS()); 267 if (normalized_triple.getEnvironmentName().empty()) 268 normalized_triple.setEnvironment(host_triple.getEnvironment()); 269 return ArchSpec(normalized_triple); 270 } 271 272 bool HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec) { 273 // To get paths related to LLDB we get the path to the executable that 274 // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB". 275 // On other posix systems, we will get .../lib(64|32)?/liblldb.so. 276 277 FileSpec lldb_file_spec( 278 Host::GetModuleFileSpecForHostAddress(reinterpret_cast<void *>( 279 reinterpret_cast<intptr_t>(HostInfoBase::GetLLDBPath)))); 280 281 // This is necessary because when running the testsuite the shlib might be a 282 // symbolic link inside the Python resource dir. 283 FileSystem::ResolveSymbolicLink(lldb_file_spec, lldb_file_spec); 284 285 // Remove the filename so that this FileSpec only represents the directory. 286 file_spec.GetDirectory() = lldb_file_spec.GetDirectory(); 287 288 return (bool)file_spec.GetDirectory(); 289 } 290 291 bool HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) { 292 return GetLLDBPath(lldb::ePathTypeLLDBShlibDir, file_spec); 293 } 294 295 bool HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec) { 296 FileSpec temp_file_spec; 297 if (!HostInfo::ComputeGlobalTempFileDirectory(temp_file_spec)) 298 return false; 299 300 std::string pid_str{llvm::to_string(Host::GetCurrentProcessID())}; 301 temp_file_spec.AppendPathComponent(pid_str); 302 if (llvm::sys::fs::create_directory(temp_file_spec.GetPath())) 303 return false; 304 305 file_spec.GetDirectory().SetCString(temp_file_spec.GetCString()); 306 return true; 307 } 308 309 bool HostInfoBase::ComputeTempFileBaseDirectory(FileSpec &file_spec) { 310 llvm::SmallVector<char, 16> tmpdir; 311 llvm::sys::path::system_temp_directory(/*ErasedOnReboot*/ true, tmpdir); 312 file_spec = FileSpec(std::string(tmpdir.data(), tmpdir.size()), true); 313 return true; 314 } 315 316 bool HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) { 317 file_spec.Clear(); 318 319 FileSpec temp_file_spec; 320 if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec)) 321 return false; 322 323 temp_file_spec.AppendPathComponent("lldb"); 324 if (llvm::sys::fs::create_directory(temp_file_spec.GetPath())) 325 return false; 326 327 file_spec.GetDirectory().SetCString(temp_file_spec.GetCString()); 328 return true; 329 } 330 331 bool HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec) { 332 // TODO(zturner): Figure out how to compute the header directory for all 333 // platforms. 334 return false; 335 } 336 337 bool HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec) { 338 // TODO(zturner): Figure out how to compute the system plugins directory for 339 // all platforms. 340 return false; 341 } 342 343 bool HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) { 344 // TODO(zturner): Figure out how to compute the user plugins directory for 345 // all platforms. 346 return false; 347 } 348 349 void HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, 350 ArchSpec &arch_64) { 351 llvm::Triple triple(llvm::sys::getProcessTriple()); 352 353 arch_32.Clear(); 354 arch_64.Clear(); 355 356 switch (triple.getArch()) { 357 default: 358 arch_32.SetTriple(triple); 359 break; 360 361 case llvm::Triple::aarch64: 362 case llvm::Triple::ppc64: 363 case llvm::Triple::ppc64le: 364 case llvm::Triple::x86_64: 365 arch_64.SetTriple(triple); 366 arch_32.SetTriple(triple.get32BitArchVariant()); 367 break; 368 369 case llvm::Triple::mips64: 370 case llvm::Triple::mips64el: 371 case llvm::Triple::sparcv9: 372 case llvm::Triple::systemz: 373 arch_64.SetTriple(triple); 374 break; 375 } 376 } 377