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