HostInfoBase.cpp revision 341825
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
31using namespace lldb;
32using namespace lldb_private;
33
34namespace {
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
43struct 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
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
68HostInfoBaseFields *g_fields = nullptr;
69}
70
71void HostInfoBase::Initialize() { g_fields = new HostInfoBaseFields(); }
72
73void HostInfoBase::Terminate() {
74  delete g_fields;
75  g_fields = nullptr;
76}
77
78llvm::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
87const 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
105llvm::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
113FileSpec 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
124FileSpec 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
136FileSpec 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
147FileSpec 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
160FileSpec 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
172FileSpec 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
185FileSpec 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
197ArchSpec 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
218bool 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::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
237bool HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) {
238  file_spec = GetShlibDir();
239  return bool(file_spec);
240}
241
242bool 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
256bool 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()), true);
260  return true;
261}
262
263bool HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) {
264  file_spec.Clear();
265
266  FileSpec temp_file_spec;
267  if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec))
268    return false;
269
270  temp_file_spec.AppendPathComponent("lldb");
271  if (llvm::sys::fs::create_directory(temp_file_spec.GetPath()))
272    return false;
273
274  file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
275  return true;
276}
277
278bool HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec) {
279  // TODO(zturner): Figure out how to compute the header directory for all
280  // platforms.
281  return false;
282}
283
284bool HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec) {
285  // TODO(zturner): Figure out how to compute the system plugins directory for
286  // all platforms.
287  return false;
288}
289
290bool HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) {
291  // TODO(zturner): Figure out how to compute the user plugins directory for
292  // all platforms.
293  return false;
294}
295
296void HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32,
297                                                  ArchSpec &arch_64) {
298  llvm::Triple triple(llvm::sys::getProcessTriple());
299
300  arch_32.Clear();
301  arch_64.Clear();
302
303  switch (triple.getArch()) {
304  default:
305    arch_32.SetTriple(triple);
306    break;
307
308  case llvm::Triple::aarch64:
309  case llvm::Triple::ppc64:
310  case llvm::Triple::ppc64le:
311  case llvm::Triple::x86_64:
312    arch_64.SetTriple(triple);
313    arch_32.SetTriple(triple.get32BitArchVariant());
314    break;
315
316  case llvm::Triple::mips64:
317  case llvm::Triple::mips64el:
318  case llvm::Triple::sparcv9:
319  case llvm::Triple::systemz:
320    arch_64.SetTriple(triple);
321    break;
322  }
323}
324