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 37 // static variables correctly in a thread safe way. Really each of the 38 // variables in HostInfoBaseFields should live in the functions in which 39 // they are used and each one should be static, but the work around is 40 // in place to avoid this 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 cleaned 48 // 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 #if defined(LLDB_DISABLE_PYTHON) 118 if (type == lldb::ePathTypePythonDir) 119 return false; 120 #endif 121 122 FileSpec *result = nullptr; 123 switch (type) { 124 case lldb::ePathTypeLLDBShlibDir: { 125 static llvm::once_flag g_once_flag; 126 static bool success = false; 127 llvm::call_once(g_once_flag, []() { 128 success = 129 HostInfo::ComputeSharedLibraryDirectory(g_fields->m_lldb_so_dir); 130 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 131 if (log) 132 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'", 133 g_fields->m_lldb_so_dir.GetPath().c_str()); 134 }); 135 if (success) 136 result = &g_fields->m_lldb_so_dir; 137 } break; 138 case lldb::ePathTypeSupportExecutableDir: { 139 static llvm::once_flag g_once_flag; 140 static bool success = false; 141 llvm::call_once(g_once_flag, []() { 142 success = HostInfo::ComputeSupportExeDirectory( 143 g_fields->m_lldb_support_exe_dir); 144 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 145 if (log) 146 log->Printf( 147 "HostInfoBase::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'", 148 g_fields->m_lldb_support_exe_dir.GetPath().c_str()); 149 }); 150 if (success) 151 result = &g_fields->m_lldb_support_exe_dir; 152 } break; 153 case lldb::ePathTypeHeaderDir: { 154 static llvm::once_flag g_once_flag; 155 static bool success = false; 156 llvm::call_once(g_once_flag, []() { 157 success = HostInfo::ComputeHeaderDirectory(g_fields->m_lldb_headers_dir); 158 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 159 if (log) 160 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeHeaderDir) => '%s'", 161 g_fields->m_lldb_headers_dir.GetPath().c_str()); 162 }); 163 if (success) 164 result = &g_fields->m_lldb_headers_dir; 165 } break; 166 case lldb::ePathTypePythonDir: { 167 static llvm::once_flag g_once_flag; 168 static bool success = false; 169 llvm::call_once(g_once_flag, []() { 170 success = HostInfo::ComputePythonDirectory(g_fields->m_lldb_python_dir); 171 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 172 if (log) 173 log->Printf("HostInfoBase::GetLLDBPath(ePathTypePythonDir) => '%s'", 174 g_fields->m_lldb_python_dir.GetPath().c_str()); 175 }); 176 if (success) 177 result = &g_fields->m_lldb_python_dir; 178 } break; 179 case lldb::ePathTypeClangDir: { 180 static llvm::once_flag g_once_flag; 181 static bool success = false; 182 llvm::call_once(g_once_flag, []() { 183 success = 184 HostInfo::ComputeClangDirectory(g_fields->m_lldb_clang_resource_dir); 185 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 186 if (log) 187 log->Printf( 188 "HostInfoBase::GetLLDBPath(ePathTypeClangResourceDir) => '%s'", 189 g_fields->m_lldb_clang_resource_dir.GetPath().c_str()); 190 }); 191 if (success) 192 result = &g_fields->m_lldb_clang_resource_dir; 193 } break; 194 case lldb::ePathTypeLLDBSystemPlugins: { 195 static llvm::once_flag g_once_flag; 196 static bool success = false; 197 llvm::call_once(g_once_flag, []() { 198 success = HostInfo::ComputeSystemPluginsDirectory( 199 g_fields->m_lldb_system_plugin_dir); 200 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 201 if (log) 202 log->Printf( 203 "HostInfoBase::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'", 204 g_fields->m_lldb_system_plugin_dir.GetPath().c_str()); 205 }); 206 if (success) 207 result = &g_fields->m_lldb_system_plugin_dir; 208 } break; 209 case lldb::ePathTypeLLDBUserPlugins: { 210 static llvm::once_flag g_once_flag; 211 static bool success = false; 212 llvm::call_once(g_once_flag, []() { 213 success = HostInfo::ComputeUserPluginsDirectory( 214 g_fields->m_lldb_user_plugin_dir); 215 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 216 if (log) 217 log->Printf( 218 "HostInfoBase::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'", 219 g_fields->m_lldb_user_plugin_dir.GetPath().c_str()); 220 }); 221 if (success) 222 result = &g_fields->m_lldb_user_plugin_dir; 223 } break; 224 case lldb::ePathTypeLLDBTempSystemDir: { 225 static llvm::once_flag g_once_flag; 226 static bool success = false; 227 llvm::call_once(g_once_flag, []() { 228 success = HostInfo::ComputeProcessTempFileDirectory( 229 g_fields->m_lldb_process_tmp_dir); 230 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 231 if (log) 232 log->Printf( 233 "HostInfoBase::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", 234 g_fields->m_lldb_process_tmp_dir.GetPath().c_str()); 235 }); 236 if (success) 237 result = &g_fields->m_lldb_process_tmp_dir; 238 } break; 239 case lldb::ePathTypeGlobalLLDBTempSystemDir: { 240 static llvm::once_flag g_once_flag; 241 static bool success = false; 242 llvm::call_once(g_once_flag, []() { 243 success = HostInfo::ComputeGlobalTempFileDirectory( 244 g_fields->m_lldb_global_tmp_dir); 245 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 246 if (log) 247 log->Printf("HostInfoBase::GetLLDBPath(" 248 "ePathTypeGlobalLLDBTempSystemDir) => '%s'", 249 g_fields->m_lldb_global_tmp_dir.GetPath().c_str()); 250 }); 251 if (success) 252 result = &g_fields->m_lldb_global_tmp_dir; 253 } break; 254 } 255 256 if (!result) 257 return false; 258 file_spec = *result; 259 return true; 260 } 261 262 ArchSpec HostInfoBase::GetAugmentedArchSpec(llvm::StringRef triple) { 263 if (triple.empty()) 264 return ArchSpec(); 265 llvm::Triple normalized_triple(llvm::Triple::normalize(triple)); 266 if (!ArchSpec::ContainsOnlyArch(normalized_triple)) 267 return ArchSpec(triple); 268 269 if (auto kind = HostInfo::ParseArchitectureKind(triple)) 270 return HostInfo::GetArchitecture(*kind); 271 272 llvm::Triple host_triple(llvm::sys::getDefaultTargetTriple()); 273 274 if (normalized_triple.getVendorName().empty()) 275 normalized_triple.setVendor(host_triple.getVendor()); 276 if (normalized_triple.getOSName().empty()) 277 normalized_triple.setOS(host_triple.getOS()); 278 if (normalized_triple.getEnvironmentName().empty()) 279 normalized_triple.setEnvironment(host_triple.getEnvironment()); 280 return ArchSpec(normalized_triple); 281 } 282 283 bool HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec) { 284 // To get paths related to LLDB we get the path to the executable that 285 // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB". 286 // On other posix systems, we will get .../lib(64|32)?/liblldb.so. 287 288 FileSpec lldb_file_spec( 289 Host::GetModuleFileSpecForHostAddress(reinterpret_cast<void *>( 290 reinterpret_cast<intptr_t>(HostInfoBase::GetLLDBPath)))); 291 292 // This is necessary because when running the testsuite the shlib might be a 293 // symbolic link inside the Python resource dir. 294 FileSystem::ResolveSymbolicLink(lldb_file_spec, lldb_file_spec); 295 296 // Remove the filename so that this FileSpec only represents the directory. 297 file_spec.GetDirectory() = lldb_file_spec.GetDirectory(); 298 299 return (bool)file_spec.GetDirectory(); 300 } 301 302 bool HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) { 303 return GetLLDBPath(lldb::ePathTypeLLDBShlibDir, file_spec); 304 } 305 306 bool HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec) { 307 FileSpec temp_file_spec; 308 if (!HostInfo::ComputeGlobalTempFileDirectory(temp_file_spec)) 309 return false; 310 311 std::string pid_str{llvm::to_string(Host::GetCurrentProcessID())}; 312 temp_file_spec.AppendPathComponent(pid_str); 313 if (llvm::sys::fs::create_directory(temp_file_spec.GetPath())) 314 return false; 315 316 file_spec.GetDirectory().SetCString(temp_file_spec.GetCString()); 317 return true; 318 } 319 320 bool HostInfoBase::ComputeTempFileBaseDirectory(FileSpec &file_spec) { 321 llvm::SmallVector<char, 16> tmpdir; 322 llvm::sys::path::system_temp_directory(/*ErasedOnReboot*/ true, tmpdir); 323 file_spec = FileSpec(std::string(tmpdir.data(), tmpdir.size()), true); 324 return true; 325 } 326 327 bool HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) { 328 file_spec.Clear(); 329 330 FileSpec temp_file_spec; 331 if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec)) 332 return false; 333 334 temp_file_spec.AppendPathComponent("lldb"); 335 if (llvm::sys::fs::create_directory(temp_file_spec.GetPath())) 336 return false; 337 338 file_spec.GetDirectory().SetCString(temp_file_spec.GetCString()); 339 return true; 340 } 341 342 bool HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec) { 343 // TODO(zturner): Figure out how to compute the header directory for all 344 // platforms. 345 return false; 346 } 347 348 bool HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec) { 349 // TODO(zturner): Figure out how to compute the system plugins directory for 350 // all platforms. 351 return false; 352 } 353 354 bool HostInfoBase::ComputeClangDirectory(FileSpec &file_spec) { return false; } 355 356 bool HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) { 357 // TODO(zturner): Figure out how to compute the user plugins directory for all 358 // platforms. 359 return false; 360 } 361 362 void HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, 363 ArchSpec &arch_64) { 364 llvm::Triple triple(llvm::sys::getProcessTriple()); 365 366 arch_32.Clear(); 367 arch_64.Clear(); 368 369 switch (triple.getArch()) { 370 default: 371 arch_32.SetTriple(triple); 372 break; 373 374 case llvm::Triple::aarch64: 375 case llvm::Triple::ppc64: 376 case llvm::Triple::ppc64le: 377 case llvm::Triple::x86_64: 378 arch_64.SetTriple(triple); 379 arch_32.SetTriple(triple.get32BitArchVariant()); 380 break; 381 382 case llvm::Triple::mips64: 383 case llvm::Triple::mips64el: 384 case llvm::Triple::sparcv9: 385 case llvm::Triple::systemz: 386 arch_64.SetTriple(triple); 387 break; 388 } 389 } 390