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