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/Core/Log.h" 14 #include "lldb/Core/StreamString.h" 15 #include "lldb/Host/FileSystem.h" 16 #include "lldb/Host/Host.h" 17 #include "lldb/Host/HostInfo.h" 18 #include "lldb/Host/HostInfoBase.h" 19 20 #include "llvm/ADT/Triple.h" 21 #include "llvm/Support/Host.h" 22 23 #include <thread> 24 25 using namespace lldb; 26 using namespace lldb_private; 27 28 namespace 29 { 30 void 31 CleanupProcessSpecificLLDBTempDir() 32 { 33 // Get the process specific LLDB temporary directory and delete it. 34 FileSpec tmpdir_file_spec; 35 if (!HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) 36 return; 37 38 // Remove the LLDB temporary directory if we have one. Set "recurse" to 39 // true to all files that were created for the LLDB process can be cleaned up. 40 FileSystem::DeleteDirectory(tmpdir_file_spec.GetDirectory().GetCString(), true); 41 } 42 43 struct HostInfoBaseFields 44 { 45 uint32_t m_number_cpus; 46 std::string m_vendor_string; 47 std::string m_os_string; 48 std::string m_host_triple; 49 50 ArchSpec m_host_arch_32; 51 ArchSpec m_host_arch_64; 52 53 FileSpec m_lldb_so_dir; 54 FileSpec m_lldb_support_exe_dir; 55 FileSpec m_lldb_headers_dir; 56 FileSpec m_lldb_python_dir; 57 FileSpec m_lldb_system_plugin_dir; 58 FileSpec m_lldb_user_plugin_dir; 59 FileSpec m_lldb_tmp_dir; 60 }; 61 62 HostInfoBaseFields *g_fields = nullptr; 63 } 64 65 #define COMPUTE_LLDB_PATH(compute_function, member_var) \ 66 { \ 67 static bool is_initialized = false; \ 68 static bool success = false; \ 69 if (!is_initialized) \ 70 { \ 71 is_initialized = true; \ 72 success = HostInfo::compute_function(member_var); \ 73 } \ 74 if (success) \ 75 result = &member_var; \ 76 } 77 78 void 79 HostInfoBase::Initialize() 80 { 81 g_fields = new HostInfoBaseFields(); 82 } 83 84 uint32_t 85 HostInfoBase::GetNumberCPUS() 86 { 87 static bool is_initialized = false; 88 if (!is_initialized) 89 { 90 g_fields->m_number_cpus = std::thread::hardware_concurrency(); 91 is_initialized = true; 92 } 93 94 return g_fields->m_number_cpus; 95 } 96 97 llvm::StringRef 98 HostInfoBase::GetVendorString() 99 { 100 static bool is_initialized = false; 101 if (!is_initialized) 102 { 103 const ArchSpec &host_arch = HostInfo::GetArchitecture(); 104 const llvm::StringRef &str_ref = host_arch.GetTriple().getVendorName(); 105 g_fields->m_vendor_string.assign(str_ref.begin(), str_ref.end()); 106 is_initialized = true; 107 } 108 return g_fields->m_vendor_string; 109 } 110 111 llvm::StringRef 112 HostInfoBase::GetOSString() 113 { 114 static bool is_initialized = false; 115 if (!is_initialized) 116 { 117 const ArchSpec &host_arch = HostInfo::GetArchitecture(); 118 const llvm::StringRef &str_ref = host_arch.GetTriple().getOSName(); 119 g_fields->m_os_string.assign(str_ref.begin(), str_ref.end()); 120 is_initialized = true; 121 } 122 return g_fields->m_os_string; 123 } 124 125 llvm::StringRef 126 HostInfoBase::GetTargetTriple() 127 { 128 static bool is_initialized = false; 129 if (!is_initialized) 130 { 131 const ArchSpec &host_arch = HostInfo::GetArchitecture(); 132 g_fields->m_host_triple = host_arch.GetTriple().getTriple(); 133 is_initialized = true; 134 } 135 return g_fields->m_host_triple; 136 } 137 138 const ArchSpec & 139 HostInfoBase::GetArchitecture(ArchitectureKind arch_kind) 140 { 141 static bool is_initialized = false; 142 if (!is_initialized) 143 { 144 HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32, g_fields->m_host_arch_64); 145 is_initialized = true; 146 } 147 148 // If an explicit 32 or 64-bit architecture was requested, return that. 149 if (arch_kind == eArchKind32) 150 return g_fields->m_host_arch_32; 151 if (arch_kind == eArchKind64) 152 return g_fields->m_host_arch_64; 153 154 // Otherwise prefer the 64-bit architecture if it is valid. 155 return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64 : g_fields->m_host_arch_32; 156 } 157 158 bool 159 HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) 160 { 161 file_spec.Clear(); 162 163 #if defined(LLDB_DISABLE_PYTHON) 164 if (type == lldb::ePathTypePythonDir) 165 return false; 166 #endif 167 168 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 169 FileSpec *result = nullptr; 170 switch (type) 171 { 172 case lldb::ePathTypeLLDBShlibDir: 173 COMPUTE_LLDB_PATH(ComputeSharedLibraryDirectory, g_fields->m_lldb_so_dir) 174 if (log) 175 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'", g_fields->m_lldb_so_dir.GetPath().c_str()); 176 break; 177 case lldb::ePathTypeSupportExecutableDir: 178 COMPUTE_LLDB_PATH(ComputeSupportExeDirectory, g_fields->m_lldb_support_exe_dir) 179 if (log) 180 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'", 181 g_fields->m_lldb_support_exe_dir.GetPath().c_str()); 182 break; 183 case lldb::ePathTypeHeaderDir: 184 COMPUTE_LLDB_PATH(ComputeHeaderDirectory, g_fields->m_lldb_headers_dir) 185 if (log) 186 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeHeaderDir) => '%s'", g_fields->m_lldb_headers_dir.GetPath().c_str()); 187 break; 188 case lldb::ePathTypePythonDir: 189 COMPUTE_LLDB_PATH(ComputePythonDirectory, g_fields->m_lldb_python_dir) 190 if (log) 191 log->Printf("HostInfoBase::GetLLDBPath(ePathTypePythonDir) => '%s'", g_fields->m_lldb_python_dir.GetPath().c_str()); 192 break; 193 case lldb::ePathTypeLLDBSystemPlugins: 194 COMPUTE_LLDB_PATH(ComputeSystemPluginsDirectory, g_fields->m_lldb_system_plugin_dir) 195 if (log) 196 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'", 197 g_fields->m_lldb_system_plugin_dir.GetPath().c_str()); 198 break; 199 case lldb::ePathTypeLLDBUserPlugins: 200 COMPUTE_LLDB_PATH(ComputeUserPluginsDirectory, g_fields->m_lldb_user_plugin_dir) 201 if (log) 202 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'", 203 g_fields->m_lldb_user_plugin_dir.GetPath().c_str()); 204 break; 205 case lldb::ePathTypeLLDBTempSystemDir: 206 COMPUTE_LLDB_PATH(ComputeTempFileDirectory, g_fields->m_lldb_tmp_dir) 207 if (log) 208 log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", g_fields->m_lldb_tmp_dir.GetPath().c_str()); 209 break; 210 } 211 212 if (!result) 213 return false; 214 file_spec = *result; 215 return true; 216 } 217 218 bool 219 HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec) 220 { 221 // To get paths related to LLDB we get the path to the executable that 222 // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB", 223 // on linux this is assumed to be the "lldb" main executable. If LLDB on 224 // linux is actually in a shared library (liblldb.so) then this function will 225 // need to be modified to "do the right thing". 226 227 FileSpec lldb_file_spec( 228 Host::GetModuleFileSpecForHostAddress(reinterpret_cast<void *>(reinterpret_cast<intptr_t>(HostInfoBase::GetLLDBPath)))); 229 230 // Remove the filename so that this FileSpec only represents the directory. 231 file_spec.GetDirectory() = lldb_file_spec.GetDirectory(); 232 233 return (bool)file_spec.GetDirectory(); 234 } 235 236 bool 237 HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) 238 { 239 return GetLLDBPath(lldb::ePathTypeLLDBShlibDir, file_spec); 240 } 241 242 bool 243 HostInfoBase::ComputeTempFileDirectory(FileSpec &file_spec) 244 { 245 const char *tmpdir_cstr = getenv("TMPDIR"); 246 if (tmpdir_cstr == NULL) 247 { 248 tmpdir_cstr = getenv("TMP"); 249 if (tmpdir_cstr == NULL) 250 tmpdir_cstr = getenv("TEMP"); 251 } 252 if (!tmpdir_cstr) 253 return false; 254 255 StreamString pid_tmpdir; 256 pid_tmpdir.Printf("%s/lldb", tmpdir_cstr); 257 if (!FileSystem::MakeDirectory(pid_tmpdir.GetString().c_str(), eFilePermissionsDirectoryDefault).Success()) 258 return false; 259 260 pid_tmpdir.Printf("/%" PRIu64, Host::GetCurrentProcessID()); 261 if (!FileSystem::MakeDirectory(pid_tmpdir.GetString().c_str(), eFilePermissionsDirectoryDefault).Success()) 262 return false; 263 264 // Make an atexit handler to clean up the process specify LLDB temp dir 265 // and all of its contents. 266 ::atexit(CleanupProcessSpecificLLDBTempDir); 267 file_spec.GetDirectory().SetCStringWithLength(pid_tmpdir.GetString().c_str(), pid_tmpdir.GetString().size()); 268 return true; 269 } 270 271 bool 272 HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec) 273 { 274 // TODO(zturner): Figure out how to compute the header directory for all platforms. 275 return false; 276 } 277 278 bool 279 HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec) 280 { 281 // TODO(zturner): Figure out how to compute the system plugins directory for all platforms. 282 return false; 283 } 284 285 bool 286 HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) 287 { 288 // TODO(zturner): Figure out how to compute the user plugins directory for all platforms. 289 return false; 290 } 291 292 void 293 HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64) 294 { 295 llvm::Triple triple(llvm::sys::getDefaultTargetTriple()); 296 297 arch_32.Clear(); 298 arch_64.Clear(); 299 300 switch (triple.getArch()) 301 { 302 default: 303 arch_32.SetTriple(triple); 304 break; 305 306 case llvm::Triple::x86_64: 307 arch_64.SetTriple(triple); 308 arch_32.SetTriple(triple.get32BitArchVariant()); 309 break; 310 311 case llvm::Triple::aarch64: 312 case llvm::Triple::mips64: 313 case llvm::Triple::sparcv9: 314 case llvm::Triple::ppc64: 315 arch_64.SetTriple(triple); 316 break; 317 } 318 } 319