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/Core/ArchSpec.h" 13 #include "lldb/Host/FileSystem.h" 14 #include "lldb/Host/Host.h" 15 #include "lldb/Host/HostInfo.h" 16 #include "lldb/Host/HostInfoBase.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 bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) { 107 file_spec.Clear(); 108 109 #if defined(LLDB_DISABLE_PYTHON) 110 if (type == lldb::ePathTypePythonDir) 111 return false; 112 #endif 113 114 FileSpec *result = nullptr; 115 switch (type) { 116 case lldb::ePathTypeLLDBShlibDir: { 117 static llvm::once_flag g_once_flag; 118 static bool success = false; 119 llvm::call_once(g_once_flag, []() { 120 success = 121 HostInfo::ComputeSharedLibraryDirectory(g_fields->m_lldb_so_dir); 122 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 123 if (log) 124 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'", 125 g_fields->m_lldb_so_dir.GetPath().c_str()); 126 }); 127 if (success) 128 result = &g_fields->m_lldb_so_dir; 129 } break; 130 case lldb::ePathTypeSupportExecutableDir: { 131 static llvm::once_flag g_once_flag; 132 static bool success = false; 133 llvm::call_once(g_once_flag, []() { 134 success = HostInfo::ComputeSupportExeDirectory( 135 g_fields->m_lldb_support_exe_dir); 136 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 137 if (log) 138 log->Printf( 139 "HostInfoBase::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'", 140 g_fields->m_lldb_support_exe_dir.GetPath().c_str()); 141 }); 142 if (success) 143 result = &g_fields->m_lldb_support_exe_dir; 144 } break; 145 case lldb::ePathTypeHeaderDir: { 146 static llvm::once_flag g_once_flag; 147 static bool success = false; 148 llvm::call_once(g_once_flag, []() { 149 success = HostInfo::ComputeHeaderDirectory(g_fields->m_lldb_headers_dir); 150 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 151 if (log) 152 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeHeaderDir) => '%s'", 153 g_fields->m_lldb_headers_dir.GetPath().c_str()); 154 }); 155 if (success) 156 result = &g_fields->m_lldb_headers_dir; 157 } break; 158 case lldb::ePathTypePythonDir: { 159 static llvm::once_flag g_once_flag; 160 static bool success = false; 161 llvm::call_once(g_once_flag, []() { 162 success = HostInfo::ComputePythonDirectory(g_fields->m_lldb_python_dir); 163 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 164 if (log) 165 log->Printf("HostInfoBase::GetLLDBPath(ePathTypePythonDir) => '%s'", 166 g_fields->m_lldb_python_dir.GetPath().c_str()); 167 }); 168 if (success) 169 result = &g_fields->m_lldb_python_dir; 170 } break; 171 case lldb::ePathTypeClangDir: { 172 static llvm::once_flag g_once_flag; 173 static bool success = false; 174 llvm::call_once(g_once_flag, []() { 175 success = 176 HostInfo::ComputeClangDirectory(g_fields->m_lldb_clang_resource_dir); 177 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 178 if (log) 179 log->Printf( 180 "HostInfoBase::GetLLDBPath(ePathTypeClangResourceDir) => '%s'", 181 g_fields->m_lldb_clang_resource_dir.GetPath().c_str()); 182 }); 183 if (success) 184 result = &g_fields->m_lldb_clang_resource_dir; 185 } break; 186 case lldb::ePathTypeLLDBSystemPlugins: { 187 static llvm::once_flag g_once_flag; 188 static bool success = false; 189 llvm::call_once(g_once_flag, []() { 190 success = HostInfo::ComputeSystemPluginsDirectory( 191 g_fields->m_lldb_system_plugin_dir); 192 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 193 if (log) 194 log->Printf( 195 "HostInfoBase::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'", 196 g_fields->m_lldb_system_plugin_dir.GetPath().c_str()); 197 }); 198 if (success) 199 result = &g_fields->m_lldb_system_plugin_dir; 200 } break; 201 case lldb::ePathTypeLLDBUserPlugins: { 202 static llvm::once_flag g_once_flag; 203 static bool success = false; 204 llvm::call_once(g_once_flag, []() { 205 success = HostInfo::ComputeUserPluginsDirectory( 206 g_fields->m_lldb_user_plugin_dir); 207 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 208 if (log) 209 log->Printf( 210 "HostInfoBase::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'", 211 g_fields->m_lldb_user_plugin_dir.GetPath().c_str()); 212 }); 213 if (success) 214 result = &g_fields->m_lldb_user_plugin_dir; 215 } break; 216 case lldb::ePathTypeLLDBTempSystemDir: { 217 static llvm::once_flag g_once_flag; 218 static bool success = false; 219 llvm::call_once(g_once_flag, []() { 220 success = HostInfo::ComputeProcessTempFileDirectory( 221 g_fields->m_lldb_process_tmp_dir); 222 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 223 if (log) 224 log->Printf( 225 "HostInfoBase::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", 226 g_fields->m_lldb_process_tmp_dir.GetPath().c_str()); 227 }); 228 if (success) 229 result = &g_fields->m_lldb_process_tmp_dir; 230 } break; 231 case lldb::ePathTypeGlobalLLDBTempSystemDir: { 232 static llvm::once_flag g_once_flag; 233 static bool success = false; 234 llvm::call_once(g_once_flag, []() { 235 success = HostInfo::ComputeGlobalTempFileDirectory( 236 g_fields->m_lldb_global_tmp_dir); 237 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 238 if (log) 239 log->Printf("HostInfoBase::GetLLDBPath(" 240 "ePathTypeGlobalLLDBTempSystemDir) => '%s'", 241 g_fields->m_lldb_global_tmp_dir.GetPath().c_str()); 242 }); 243 if (success) 244 result = &g_fields->m_lldb_global_tmp_dir; 245 } break; 246 } 247 248 if (!result) 249 return false; 250 file_spec = *result; 251 return true; 252 } 253 254 bool HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec) { 255 // To get paths related to LLDB we get the path to the executable that 256 // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB", 257 // on linux this is assumed to be the "lldb" main executable. If LLDB on 258 // linux is actually in a shared library (liblldb.so) then this function will 259 // need to be modified to "do the right thing". 260 261 FileSpec lldb_file_spec( 262 Host::GetModuleFileSpecForHostAddress(reinterpret_cast<void *>( 263 reinterpret_cast<intptr_t>(HostInfoBase::GetLLDBPath)))); 264 265 // This is necessary because when running the testsuite the shlib might be a 266 // symbolic link inside the Python resource dir. 267 FileSystem::ResolveSymbolicLink(lldb_file_spec, lldb_file_spec); 268 269 // Remove the filename so that this FileSpec only represents the directory. 270 file_spec.GetDirectory() = lldb_file_spec.GetDirectory(); 271 272 return (bool)file_spec.GetDirectory(); 273 } 274 275 bool HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) { 276 return GetLLDBPath(lldb::ePathTypeLLDBShlibDir, file_spec); 277 } 278 279 bool HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec) { 280 FileSpec temp_file_spec; 281 if (!HostInfo::ComputeGlobalTempFileDirectory(temp_file_spec)) 282 return false; 283 284 std::string pid_str{llvm::to_string(Host::GetCurrentProcessID())}; 285 temp_file_spec.AppendPathComponent(pid_str); 286 if (llvm::sys::fs::create_directory(temp_file_spec.GetPath())) 287 return false; 288 289 file_spec.GetDirectory().SetCString(temp_file_spec.GetCString()); 290 return true; 291 } 292 293 bool HostInfoBase::ComputeTempFileBaseDirectory(FileSpec &file_spec) { 294 llvm::SmallVector<char, 16> tmpdir; 295 llvm::sys::path::system_temp_directory(/*ErasedOnReboot*/ true, tmpdir); 296 file_spec = FileSpec(std::string(tmpdir.data(), tmpdir.size()), true); 297 return true; 298 } 299 300 bool HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) { 301 file_spec.Clear(); 302 303 FileSpec temp_file_spec; 304 if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec)) 305 return false; 306 307 temp_file_spec.AppendPathComponent("lldb"); 308 if (llvm::sys::fs::create_directory(temp_file_spec.GetPath())) 309 return false; 310 311 file_spec.GetDirectory().SetCString(temp_file_spec.GetCString()); 312 return true; 313 } 314 315 bool HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec) { 316 // TODO(zturner): Figure out how to compute the header directory for all 317 // platforms. 318 return false; 319 } 320 321 bool HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec) { 322 // TODO(zturner): Figure out how to compute the system plugins directory for 323 // all platforms. 324 return false; 325 } 326 327 bool HostInfoBase::ComputeClangDirectory(FileSpec &file_spec) { return false; } 328 329 bool HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) { 330 // TODO(zturner): Figure out how to compute the user plugins directory for all 331 // platforms. 332 return false; 333 } 334 335 void HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, 336 ArchSpec &arch_64) { 337 llvm::Triple triple(llvm::sys::getProcessTriple()); 338 339 arch_32.Clear(); 340 arch_64.Clear(); 341 342 switch (triple.getArch()) { 343 default: 344 arch_32.SetTriple(triple); 345 break; 346 347 case llvm::Triple::aarch64: 348 case llvm::Triple::ppc64: 349 case llvm::Triple::x86_64: 350 arch_64.SetTriple(triple); 351 arch_32.SetTriple(triple.get32BitArchVariant()); 352 break; 353 354 case llvm::Triple::mips64: 355 case llvm::Triple::mips64el: 356 case llvm::Triple::sparcv9: 357 case llvm::Triple::systemz: 358 arch_64.SetTriple(triple); 359 break; 360 } 361 } 362