HostInfoBase.cpp revision 355940
1110285Snyan//===-- HostInfoBase.cpp ----------------------------------------*- C++ -*-===//
2110285Snyan//
3110329Stakawata// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4110333Snyan// See https://llvm.org/LICENSE.txt for license information.
5110285Snyan// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6110285Snyan//
7110285Snyan//===----------------------------------------------------------------------===//
8110285Snyan
9110285Snyan#include "lldb/Host/Config.h"
10110285Snyan
11110285Snyan#include "lldb/Host/FileSystem.h"
12110285Snyan#include "lldb/Host/Host.h"
13110285Snyan#include "lldb/Host/HostInfo.h"
14110285Snyan#include "lldb/Host/HostInfoBase.h"
15110285Snyan#include "lldb/Utility/ArchSpec.h"
16110285Snyan#include "lldb/Utility/Log.h"
17110285Snyan#include "lldb/Utility/StreamString.h"
18110285Snyan
19110285Snyan#include "llvm/ADT/StringExtras.h"
20110285Snyan#include "llvm/ADT/Triple.h"
21110285Snyan#include "llvm/Support/Host.h"
22110285Snyan#include "llvm/Support/Path.h"
23110285Snyan#include "llvm/Support/ScopedPrinter.h"
24110285Snyan#include "llvm/Support/Threading.h"
25110333Snyan#include "llvm/Support/raw_ostream.h"
26110285Snyan
27110285Snyan#include <mutex>
28110285Snyan#include <thread>
29110285Snyan
30110285Snyanusing namespace lldb;
31110285Snyanusing namespace lldb_private;
32110285Snyan
33110285Snyannamespace {
34110285Snyan// The HostInfoBaseFields is a work around for windows not supporting static
35110285Snyan// variables correctly in a thread safe way. Really each of the variables in
36110285Snyan// HostInfoBaseFields should live in the functions in which they are used and
37110285Snyan// each one should be static, but the work around is in place to avoid this
38110285Snyan// restriction. Ick.
39110285Snyan
40110285Snyanstruct HostInfoBaseFields {
41110285Snyan  ~HostInfoBaseFields() {
42110285Snyan    if (FileSystem::Instance().Exists(m_lldb_process_tmp_dir)) {
43110285Snyan      // Remove the LLDB temporary directory if we have one. Set "recurse" to
44110285Snyan      // true to all files that were created for the LLDB process can be
45110285Snyan      // cleaned up.
46110285Snyan      llvm::sys::fs::remove_directories(m_lldb_process_tmp_dir.GetPath());
47110285Snyan    }
48110285Snyan  }
49110285Snyan
50110285Snyan  std::string m_host_triple;
51110285Snyan
52110285Snyan  ArchSpec m_host_arch_32;
53110285Snyan  ArchSpec m_host_arch_64;
54110285Snyan
55110285Snyan  FileSpec m_lldb_so_dir;
56110285Snyan  FileSpec m_lldb_support_exe_dir;
57110285Snyan  FileSpec m_lldb_headers_dir;
58110285Snyan  FileSpec m_lldb_clang_resource_dir;
59110285Snyan  FileSpec m_lldb_system_plugin_dir;
60110285Snyan  FileSpec m_lldb_user_plugin_dir;
61110285Snyan  FileSpec m_lldb_process_tmp_dir;
62110285Snyan  FileSpec m_lldb_global_tmp_dir;
63110285Snyan};
64110285Snyan
65110285SnyanHostInfoBaseFields *g_fields = nullptr;
66110285Snyan}
67110285Snyan
68110285Snyanvoid HostInfoBase::Initialize() { g_fields = new HostInfoBaseFields(); }
69110285Snyan
70110285Snyanvoid HostInfoBase::Terminate() {
71110285Snyan  delete g_fields;
72110285Snyan  g_fields = nullptr;
73110285Snyan}
74110285Snyan
75110285Snyanllvm::StringRef HostInfoBase::GetTargetTriple() {
76110285Snyan  static llvm::once_flag g_once_flag;
77110285Snyan  llvm::call_once(g_once_flag, []() {
78110285Snyan    g_fields->m_host_triple =
79110285Snyan        HostInfo::GetArchitecture().GetTriple().getTriple();
80110285Snyan  });
81110285Snyan  return g_fields->m_host_triple;
82110285Snyan}
83110285Snyan
84110285Snyanconst ArchSpec &HostInfoBase::GetArchitecture(ArchitectureKind arch_kind) {
85110285Snyan  static llvm::once_flag g_once_flag;
86110285Snyan  llvm::call_once(g_once_flag, []() {
87110285Snyan    HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32,
88110285Snyan                                             g_fields->m_host_arch_64);
89110285Snyan  });
90110285Snyan
91110285Snyan  // If an explicit 32 or 64-bit architecture was requested, return that.
92110285Snyan  if (arch_kind == eArchKind32)
93110285Snyan    return g_fields->m_host_arch_32;
94110285Snyan  if (arch_kind == eArchKind64)
95110285Snyan    return g_fields->m_host_arch_64;
96110285Snyan
97110285Snyan  // Otherwise prefer the 64-bit architecture if it is valid.
98110285Snyan  return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64
99110285Snyan                                              : g_fields->m_host_arch_32;
100110285Snyan}
101110285Snyan
102110285Snyanllvm::Optional<HostInfoBase::ArchitectureKind> HostInfoBase::ParseArchitectureKind(llvm::StringRef kind) {
103110285Snyan  return llvm::StringSwitch<llvm::Optional<ArchitectureKind>>(kind)
104110285Snyan      .Case(LLDB_ARCH_DEFAULT, eArchKindDefault)
105110285Snyan      .Case(LLDB_ARCH_DEFAULT_32BIT, eArchKind32)
106110285Snyan      .Case(LLDB_ARCH_DEFAULT_64BIT, eArchKind64)
107110285Snyan      .Default(llvm::None);
108110285Snyan}
109110285Snyan
110110285SnyanFileSpec HostInfoBase::GetShlibDir() {
111  static llvm::once_flag g_once_flag;
112  static bool success = false;
113  llvm::call_once(g_once_flag, []() {
114    success = HostInfo::ComputeSharedLibraryDirectory(g_fields->m_lldb_so_dir);
115    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
116    LLDB_LOG(log, "shlib dir -> `{0}`", g_fields->m_lldb_so_dir);
117  });
118  return success ? g_fields->m_lldb_so_dir : FileSpec();
119}
120
121FileSpec HostInfoBase::GetSupportExeDir() {
122  static llvm::once_flag g_once_flag;
123  static bool success = false;
124  llvm::call_once(g_once_flag, []() {
125    success =
126        HostInfo::ComputeSupportExeDirectory(g_fields->m_lldb_support_exe_dir);
127    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
128    LLDB_LOG(log, "support exe dir -> `{0}`", g_fields->m_lldb_support_exe_dir);
129  });
130  return success ? g_fields->m_lldb_support_exe_dir : FileSpec();
131}
132
133FileSpec HostInfoBase::GetHeaderDir() {
134  static llvm::once_flag g_once_flag;
135  static bool success = false;
136  llvm::call_once(g_once_flag, []() {
137    success = HostInfo::ComputeHeaderDirectory(g_fields->m_lldb_headers_dir);
138    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
139    LLDB_LOG(log, "header dir -> `{0}`", g_fields->m_lldb_headers_dir);
140  });
141  return success ? g_fields->m_lldb_headers_dir : FileSpec();
142}
143
144FileSpec HostInfoBase::GetSystemPluginDir() {
145  static llvm::once_flag g_once_flag;
146  static bool success = false;
147  llvm::call_once(g_once_flag, []() {
148    success = HostInfo::ComputeSystemPluginsDirectory(
149        g_fields->m_lldb_system_plugin_dir);
150    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
151    LLDB_LOG(log, "system plugin dir -> `{0}`",
152             g_fields->m_lldb_system_plugin_dir);
153  });
154  return success ? g_fields->m_lldb_system_plugin_dir : FileSpec();
155}
156
157FileSpec HostInfoBase::GetUserPluginDir() {
158  static llvm::once_flag g_once_flag;
159  static bool success = false;
160  llvm::call_once(g_once_flag, []() {
161    success =
162        HostInfo::ComputeUserPluginsDirectory(g_fields->m_lldb_user_plugin_dir);
163    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
164    LLDB_LOG(log, "user plugin dir -> `{0}`", g_fields->m_lldb_user_plugin_dir);
165  });
166  return success ? g_fields->m_lldb_user_plugin_dir : FileSpec();
167}
168
169FileSpec HostInfoBase::GetProcessTempDir() {
170  static llvm::once_flag g_once_flag;
171  static bool success = false;
172  llvm::call_once(g_once_flag, []() {
173    success = HostInfo::ComputeProcessTempFileDirectory(
174        g_fields->m_lldb_process_tmp_dir);
175    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
176    LLDB_LOG(log, "process temp dir -> `{0}`",
177             g_fields->m_lldb_process_tmp_dir);
178  });
179  return success ? g_fields->m_lldb_process_tmp_dir : FileSpec();
180}
181
182FileSpec HostInfoBase::GetGlobalTempDir() {
183  static llvm::once_flag g_once_flag;
184  static bool success = false;
185  llvm::call_once(g_once_flag, []() {
186    success = HostInfo::ComputeGlobalTempFileDirectory(
187        g_fields->m_lldb_global_tmp_dir);
188    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
189    LLDB_LOG(log, "global temp dir -> `{0}`", g_fields->m_lldb_global_tmp_dir);
190  });
191  return success ? g_fields->m_lldb_global_tmp_dir : FileSpec();
192}
193
194ArchSpec HostInfoBase::GetAugmentedArchSpec(llvm::StringRef triple) {
195  if (triple.empty())
196    return ArchSpec();
197  llvm::Triple normalized_triple(llvm::Triple::normalize(triple));
198  if (!ArchSpec::ContainsOnlyArch(normalized_triple))
199    return ArchSpec(triple);
200
201  if (auto kind = HostInfo::ParseArchitectureKind(triple))
202    return HostInfo::GetArchitecture(*kind);
203
204  llvm::Triple host_triple(llvm::sys::getDefaultTargetTriple());
205
206  if (normalized_triple.getVendorName().empty())
207    normalized_triple.setVendor(host_triple.getVendor());
208  if (normalized_triple.getOSName().empty())
209    normalized_triple.setOS(host_triple.getOS());
210  if (normalized_triple.getEnvironmentName().empty())
211    normalized_triple.setEnvironment(host_triple.getEnvironment());
212  return ArchSpec(normalized_triple);
213}
214
215bool HostInfoBase::ComputePathRelativeToLibrary(FileSpec &file_spec,
216                                                llvm::StringRef dir) {
217  Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
218
219  FileSpec lldb_file_spec = GetShlibDir();
220  if (!lldb_file_spec)
221    return false;
222
223  std::string raw_path = lldb_file_spec.GetPath();
224  if (log)
225    log->Printf("HostInfo::%s() attempting to "
226                "derive the path %s relative to liblldb install path: %s",
227                __FUNCTION__, dir.data(), raw_path.c_str());
228
229  // Drop bin (windows) or lib
230  llvm::StringRef parent_path = llvm::sys::path::parent_path(raw_path);
231  if (parent_path.empty()) {
232    if (log)
233      log->Printf("HostInfo::%s() failed to find liblldb within the shared "
234                  "lib path",
235                  __FUNCTION__);
236    return false;
237  }
238
239  raw_path = (parent_path + dir).str();
240  if (log)
241    log->Printf("HostInfo::%s() derived the path as: %s", __FUNCTION__,
242                raw_path.c_str());
243  file_spec.GetDirectory().SetString(raw_path);
244  return (bool)file_spec.GetDirectory();
245}
246
247bool HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec) {
248  // To get paths related to LLDB we get the path to the executable that
249  // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB".
250  // On other posix systems, we will get .../lib(64|32)?/liblldb.so.
251
252  FileSpec lldb_file_spec(Host::GetModuleFileSpecForHostAddress(
253      reinterpret_cast<void *>(reinterpret_cast<intptr_t>(
254          HostInfoBase::ComputeSharedLibraryDirectory))));
255
256  // This is necessary because when running the testsuite the shlib might be a
257  // symbolic link inside the Python resource dir.
258  FileSystem::Instance().ResolveSymbolicLink(lldb_file_spec, lldb_file_spec);
259
260  // Remove the filename so that this FileSpec only represents the directory.
261  file_spec.GetDirectory() = lldb_file_spec.GetDirectory();
262
263  return (bool)file_spec.GetDirectory();
264}
265
266bool HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) {
267  file_spec = GetShlibDir();
268  return bool(file_spec);
269}
270
271bool HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec) {
272  FileSpec temp_file_spec;
273  if (!HostInfo::ComputeGlobalTempFileDirectory(temp_file_spec))
274    return false;
275
276  std::string pid_str{llvm::to_string(Host::GetCurrentProcessID())};
277  temp_file_spec.AppendPathComponent(pid_str);
278  if (llvm::sys::fs::create_directory(temp_file_spec.GetPath()))
279    return false;
280
281  file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
282  return true;
283}
284
285bool HostInfoBase::ComputeTempFileBaseDirectory(FileSpec &file_spec) {
286  llvm::SmallVector<char, 16> tmpdir;
287  llvm::sys::path::system_temp_directory(/*ErasedOnReboot*/ true, tmpdir);
288  file_spec = FileSpec(std::string(tmpdir.data(), tmpdir.size()));
289  FileSystem::Instance().Resolve(file_spec);
290  return true;
291}
292
293bool HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) {
294  file_spec.Clear();
295
296  FileSpec temp_file_spec;
297  if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec))
298    return false;
299
300  temp_file_spec.AppendPathComponent("lldb");
301  if (llvm::sys::fs::create_directory(temp_file_spec.GetPath()))
302    return false;
303
304  file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
305  return true;
306}
307
308bool HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec) {
309  // TODO(zturner): Figure out how to compute the header directory for all
310  // platforms.
311  return false;
312}
313
314bool HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec) {
315  // TODO(zturner): Figure out how to compute the system plugins directory for
316  // all platforms.
317  return false;
318}
319
320bool HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) {
321  // TODO(zturner): Figure out how to compute the user plugins directory for
322  // all platforms.
323  return false;
324}
325
326void HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32,
327                                                  ArchSpec &arch_64) {
328  llvm::Triple triple(llvm::sys::getProcessTriple());
329
330  arch_32.Clear();
331  arch_64.Clear();
332
333  switch (triple.getArch()) {
334  default:
335    arch_32.SetTriple(triple);
336    break;
337
338  case llvm::Triple::aarch64:
339  case llvm::Triple::ppc64:
340  case llvm::Triple::ppc64le:
341  case llvm::Triple::x86_64:
342    arch_64.SetTriple(triple);
343    arch_32.SetTriple(triple.get32BitArchVariant());
344    break;
345
346  case llvm::Triple::mips64:
347  case llvm::Triple::mips64el:
348  case llvm::Triple::sparcv9:
349  case llvm::Triple::systemz:
350    arch_64.SetTriple(triple);
351    break;
352  }
353}
354