1275072Semaste//===-- HostInfoBase.cpp ----------------------------------------*- C++ -*-===//
2275072Semaste//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6275072Semaste//
7275072Semaste//===----------------------------------------------------------------------===//
8275072Semaste
9275072Semaste#include "lldb/Host/Config.h"
10275072Semaste
11275072Semaste#include "lldb/Host/FileSystem.h"
12275072Semaste#include "lldb/Host/Host.h"
13275072Semaste#include "lldb/Host/HostInfo.h"
14275072Semaste#include "lldb/Host/HostInfoBase.h"
15327952Sdim#include "lldb/Utility/ArchSpec.h"
16321369Sdim#include "lldb/Utility/Log.h"
17321369Sdim#include "lldb/Utility/StreamString.h"
18275072Semaste
19314564Sdim#include "llvm/ADT/StringExtras.h"
20275072Semaste#include "llvm/ADT/Triple.h"
21275072Semaste#include "llvm/Support/Host.h"
22296417Sdim#include "llvm/Support/Path.h"
23314564Sdim#include "llvm/Support/ScopedPrinter.h"
24321369Sdim#include "llvm/Support/Threading.h"
25280031Sdim#include "llvm/Support/raw_ostream.h"
26275072Semaste
27321369Sdim#include <mutex>
28275072Semaste#include <thread>
29275072Semaste
30275072Semasteusing namespace lldb;
31275072Semasteusing namespace lldb_private;
32275072Semaste
33314564Sdimnamespace {
34341825Sdim// The HostInfoBaseFields is a work around for windows not supporting static
35341825Sdim// variables correctly in a thread safe way. Really each of the variables in
36341825Sdim// HostInfoBaseFields should live in the functions in which they are used and
37341825Sdim// each one should be static, but the work around is in place to avoid this
38341825Sdim// restriction. Ick.
39275072Semaste
40314564Sdimstruct HostInfoBaseFields {
41314564Sdim  ~HostInfoBaseFields() {
42344779Sdim    if (FileSystem::Instance().Exists(m_lldb_process_tmp_dir)) {
43314564Sdim      // Remove the LLDB temporary directory if we have one. Set "recurse" to
44341825Sdim      // true to all files that were created for the LLDB process can be
45341825Sdim      // cleaned up.
46321369Sdim      llvm::sys::fs::remove_directories(m_lldb_process_tmp_dir.GetPath());
47314564Sdim    }
48314564Sdim  }
49309124Sdim
50360784Sdim  llvm::once_flag m_host_triple_once;
51360784Sdim  llvm::Triple m_host_triple;
52275072Semaste
53360784Sdim  llvm::once_flag m_host_arch_once;
54314564Sdim  ArchSpec m_host_arch_32;
55314564Sdim  ArchSpec m_host_arch_64;
56275072Semaste
57360784Sdim  llvm::once_flag m_lldb_so_dir_once;
58314564Sdim  FileSpec m_lldb_so_dir;
59360784Sdim  llvm::once_flag m_lldb_support_exe_dir_once;
60314564Sdim  FileSpec m_lldb_support_exe_dir;
61360784Sdim  llvm::once_flag m_lldb_headers_dir_once;
62314564Sdim  FileSpec m_lldb_headers_dir;
63360784Sdim  llvm::once_flag m_lldb_clang_resource_dir_once;
64314564Sdim  FileSpec m_lldb_clang_resource_dir;
65360784Sdim  llvm::once_flag m_lldb_system_plugin_dir_once;
66314564Sdim  FileSpec m_lldb_system_plugin_dir;
67360784Sdim  llvm::once_flag m_lldb_user_plugin_dir_once;
68314564Sdim  FileSpec m_lldb_user_plugin_dir;
69360784Sdim  llvm::once_flag m_lldb_process_tmp_dir_once;
70314564Sdim  FileSpec m_lldb_process_tmp_dir;
71360784Sdim  llvm::once_flag m_lldb_global_tmp_dir_once;
72314564Sdim  FileSpec m_lldb_global_tmp_dir;
73314564Sdim};
74275072Semaste
75314564SdimHostInfoBaseFields *g_fields = nullptr;
76275072Semaste}
77275072Semaste
78314564Sdimvoid HostInfoBase::Initialize() { g_fields = new HostInfoBaseFields(); }
79309124Sdim
80314564Sdimvoid HostInfoBase::Terminate() {
81314564Sdim  delete g_fields;
82314564Sdim  g_fields = nullptr;
83275072Semaste}
84275072Semaste
85360784Sdimllvm::Triple HostInfoBase::GetTargetTriple() {
86360784Sdim  llvm::call_once(g_fields->m_host_triple_once, []() {
87314564Sdim    g_fields->m_host_triple =
88360784Sdim        HostInfo::GetArchitecture().GetTriple();
89314564Sdim  });
90314564Sdim  return g_fields->m_host_triple;
91275072Semaste}
92275072Semaste
93314564Sdimconst ArchSpec &HostInfoBase::GetArchitecture(ArchitectureKind arch_kind) {
94360784Sdim  llvm::call_once(g_fields->m_host_arch_once, []() {
95314564Sdim    HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32,
96314564Sdim                                             g_fields->m_host_arch_64);
97314564Sdim  });
98275072Semaste
99314564Sdim  // If an explicit 32 or 64-bit architecture was requested, return that.
100314564Sdim  if (arch_kind == eArchKind32)
101314564Sdim    return g_fields->m_host_arch_32;
102314564Sdim  if (arch_kind == eArchKind64)
103314564Sdim    return g_fields->m_host_arch_64;
104275072Semaste
105314564Sdim  // Otherwise prefer the 64-bit architecture if it is valid.
106314564Sdim  return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64
107314564Sdim                                              : g_fields->m_host_arch_32;
108275072Semaste}
109275072Semaste
110327952Sdimllvm::Optional<HostInfoBase::ArchitectureKind> HostInfoBase::ParseArchitectureKind(llvm::StringRef kind) {
111327952Sdim  return llvm::StringSwitch<llvm::Optional<ArchitectureKind>>(kind)
112327952Sdim      .Case(LLDB_ARCH_DEFAULT, eArchKindDefault)
113327952Sdim      .Case(LLDB_ARCH_DEFAULT_32BIT, eArchKind32)
114327952Sdim      .Case(LLDB_ARCH_DEFAULT_64BIT, eArchKind64)
115327952Sdim      .Default(llvm::None);
116327952Sdim}
117327952Sdim
118341825SdimFileSpec HostInfoBase::GetShlibDir() {
119360784Sdim  llvm::call_once(g_fields->m_lldb_so_dir_once, []() {
120360784Sdim    if (!HostInfo::ComputeSharedLibraryDirectory(g_fields->m_lldb_so_dir))
121360784Sdim      g_fields->m_lldb_so_dir = FileSpec();
122341825Sdim    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
123341825Sdim    LLDB_LOG(log, "shlib dir -> `{0}`", g_fields->m_lldb_so_dir);
124341825Sdim  });
125360784Sdim  return g_fields->m_lldb_so_dir;
126341825Sdim}
127275072Semaste
128341825SdimFileSpec HostInfoBase::GetSupportExeDir() {
129360784Sdim  llvm::call_once(g_fields->m_lldb_support_exe_dir_once, []() {
130360784Sdim    if (!HostInfo::ComputeSupportExeDirectory(g_fields->m_lldb_support_exe_dir))
131360784Sdim      g_fields->m_lldb_support_exe_dir = FileSpec();
132341825Sdim    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
133341825Sdim    LLDB_LOG(log, "support exe dir -> `{0}`", g_fields->m_lldb_support_exe_dir);
134341825Sdim  });
135360784Sdim  return g_fields->m_lldb_support_exe_dir;
136341825Sdim}
137275072Semaste
138341825SdimFileSpec HostInfoBase::GetHeaderDir() {
139360784Sdim  llvm::call_once(g_fields->m_lldb_headers_dir_once, []() {
140360784Sdim    if (!HostInfo::ComputeHeaderDirectory(g_fields->m_lldb_headers_dir))
141360784Sdim      g_fields->m_lldb_headers_dir = FileSpec();
142341825Sdim    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
143341825Sdim    LLDB_LOG(log, "header dir -> `{0}`", g_fields->m_lldb_headers_dir);
144341825Sdim  });
145360784Sdim  return g_fields->m_lldb_headers_dir;
146341825Sdim}
147275072Semaste
148341825SdimFileSpec HostInfoBase::GetSystemPluginDir() {
149360784Sdim  llvm::call_once(g_fields->m_lldb_system_plugin_dir_once, []() {
150360784Sdim    if (!HostInfo::ComputeSystemPluginsDirectory(g_fields->m_lldb_system_plugin_dir))
151360784Sdim      g_fields->m_lldb_system_plugin_dir = FileSpec();
152341825Sdim    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
153341825Sdim    LLDB_LOG(log, "system plugin dir -> `{0}`",
154341825Sdim             g_fields->m_lldb_system_plugin_dir);
155341825Sdim  });
156360784Sdim  return g_fields->m_lldb_system_plugin_dir;
157275072Semaste}
158275072Semaste
159341825SdimFileSpec HostInfoBase::GetUserPluginDir() {
160360784Sdim  llvm::call_once(g_fields->m_lldb_user_plugin_dir_once, []() {
161360784Sdim    if (!HostInfo::ComputeUserPluginsDirectory(g_fields->m_lldb_user_plugin_dir))
162360784Sdim      g_fields->m_lldb_user_plugin_dir = FileSpec();
163341825Sdim    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
164341825Sdim    LLDB_LOG(log, "user plugin dir -> `{0}`", g_fields->m_lldb_user_plugin_dir);
165341825Sdim  });
166360784Sdim  return g_fields->m_lldb_user_plugin_dir;
167341825Sdim}
168341825Sdim
169341825SdimFileSpec HostInfoBase::GetProcessTempDir() {
170360784Sdim  llvm::call_once(g_fields->m_lldb_process_tmp_dir_once, []() {
171360784Sdim    if (!HostInfo::ComputeProcessTempFileDirectory( g_fields->m_lldb_process_tmp_dir))
172360784Sdim      g_fields->m_lldb_process_tmp_dir = FileSpec();
173341825Sdim    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
174341825Sdim    LLDB_LOG(log, "process temp dir -> `{0}`",
175341825Sdim             g_fields->m_lldb_process_tmp_dir);
176341825Sdim  });
177360784Sdim  return g_fields->m_lldb_process_tmp_dir;
178341825Sdim}
179341825Sdim
180341825SdimFileSpec HostInfoBase::GetGlobalTempDir() {
181360784Sdim  llvm::call_once(g_fields->m_lldb_global_tmp_dir_once, []() {
182360784Sdim    if (!HostInfo::ComputeGlobalTempFileDirectory( g_fields->m_lldb_global_tmp_dir))
183360784Sdim      g_fields->m_lldb_global_tmp_dir = FileSpec();
184360784Sdim
185341825Sdim    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
186341825Sdim    LLDB_LOG(log, "global temp dir -> `{0}`", g_fields->m_lldb_global_tmp_dir);
187341825Sdim  });
188360784Sdim  return g_fields->m_lldb_global_tmp_dir;
189341825Sdim}
190341825Sdim
191327952SdimArchSpec HostInfoBase::GetAugmentedArchSpec(llvm::StringRef triple) {
192327952Sdim  if (triple.empty())
193327952Sdim    return ArchSpec();
194327952Sdim  llvm::Triple normalized_triple(llvm::Triple::normalize(triple));
195327952Sdim  if (!ArchSpec::ContainsOnlyArch(normalized_triple))
196327952Sdim    return ArchSpec(triple);
197327952Sdim
198327952Sdim  if (auto kind = HostInfo::ParseArchitectureKind(triple))
199327952Sdim    return HostInfo::GetArchitecture(*kind);
200327952Sdim
201327952Sdim  llvm::Triple host_triple(llvm::sys::getDefaultTargetTriple());
202327952Sdim
203327952Sdim  if (normalized_triple.getVendorName().empty())
204327952Sdim    normalized_triple.setVendor(host_triple.getVendor());
205327952Sdim  if (normalized_triple.getOSName().empty())
206327952Sdim    normalized_triple.setOS(host_triple.getOS());
207327952Sdim  if (normalized_triple.getEnvironmentName().empty())
208327952Sdim    normalized_triple.setEnvironment(host_triple.getEnvironment());
209327952Sdim  return ArchSpec(normalized_triple);
210327952Sdim}
211327952Sdim
212353358Sdimbool HostInfoBase::ComputePathRelativeToLibrary(FileSpec &file_spec,
213353358Sdim                                                llvm::StringRef dir) {
214353358Sdim  Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
215353358Sdim
216353358Sdim  FileSpec lldb_file_spec = GetShlibDir();
217353358Sdim  if (!lldb_file_spec)
218353358Sdim    return false;
219353358Sdim
220353358Sdim  std::string raw_path = lldb_file_spec.GetPath();
221360784Sdim  LLDB_LOGF(log,
222360784Sdim            "HostInfo::%s() attempting to "
223360784Sdim            "derive the path %s relative to liblldb install path: %s",
224360784Sdim            __FUNCTION__, dir.data(), raw_path.c_str());
225353358Sdim
226353358Sdim  // Drop bin (windows) or lib
227353358Sdim  llvm::StringRef parent_path = llvm::sys::path::parent_path(raw_path);
228353358Sdim  if (parent_path.empty()) {
229360784Sdim    LLDB_LOGF(log,
230360784Sdim              "HostInfo::%s() failed to find liblldb within the shared "
231360784Sdim              "lib path",
232360784Sdim              __FUNCTION__);
233353358Sdim    return false;
234353358Sdim  }
235353358Sdim
236353358Sdim  raw_path = (parent_path + dir).str();
237360784Sdim  LLDB_LOGF(log, "HostInfo::%s() derived the path as: %s", __FUNCTION__,
238360784Sdim            raw_path.c_str());
239353358Sdim  file_spec.GetDirectory().SetString(raw_path);
240353358Sdim  return (bool)file_spec.GetDirectory();
241353358Sdim}
242353358Sdim
243314564Sdimbool HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec) {
244314564Sdim  // To get paths related to LLDB we get the path to the executable that
245341825Sdim  // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB".
246341825Sdim  // On other posix systems, we will get .../lib(64|32)?/liblldb.so.
247275072Semaste
248341825Sdim  FileSpec lldb_file_spec(Host::GetModuleFileSpecForHostAddress(
249360784Sdim      reinterpret_cast<void *>(
250360784Sdim          HostInfoBase::ComputeSharedLibraryDirectory)));
251275072Semaste
252314564Sdim  // This is necessary because when running the testsuite the shlib might be a
253314564Sdim  // symbolic link inside the Python resource dir.
254344779Sdim  FileSystem::Instance().ResolveSymbolicLink(lldb_file_spec, lldb_file_spec);
255314564Sdim
256314564Sdim  // Remove the filename so that this FileSpec only represents the directory.
257314564Sdim  file_spec.GetDirectory() = lldb_file_spec.GetDirectory();
258314564Sdim
259314564Sdim  return (bool)file_spec.GetDirectory();
260275072Semaste}
261275072Semaste
262314564Sdimbool HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) {
263341825Sdim  file_spec = GetShlibDir();
264341825Sdim  return bool(file_spec);
265275072Semaste}
266275072Semaste
267314564Sdimbool HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec) {
268314564Sdim  FileSpec temp_file_spec;
269314564Sdim  if (!HostInfo::ComputeGlobalTempFileDirectory(temp_file_spec))
270314564Sdim    return false;
271288943Sdim
272314564Sdim  std::string pid_str{llvm::to_string(Host::GetCurrentProcessID())};
273314564Sdim  temp_file_spec.AppendPathComponent(pid_str);
274321369Sdim  if (llvm::sys::fs::create_directory(temp_file_spec.GetPath()))
275314564Sdim    return false;
276288943Sdim
277314564Sdim  file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
278314564Sdim  return true;
279288943Sdim}
280288943Sdim
281314564Sdimbool HostInfoBase::ComputeTempFileBaseDirectory(FileSpec &file_spec) {
282314564Sdim  llvm::SmallVector<char, 16> tmpdir;
283314564Sdim  llvm::sys::path::system_temp_directory(/*ErasedOnReboot*/ true, tmpdir);
284344779Sdim  file_spec = FileSpec(std::string(tmpdir.data(), tmpdir.size()));
285344779Sdim  FileSystem::Instance().Resolve(file_spec);
286314564Sdim  return true;
287288943Sdim}
288288943Sdim
289314564Sdimbool HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) {
290314564Sdim  file_spec.Clear();
291288943Sdim
292314564Sdim  FileSpec temp_file_spec;
293314564Sdim  if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec))
294314564Sdim    return false;
295275072Semaste
296314564Sdim  temp_file_spec.AppendPathComponent("lldb");
297321369Sdim  if (llvm::sys::fs::create_directory(temp_file_spec.GetPath()))
298314564Sdim    return false;
299275072Semaste
300314564Sdim  file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
301314564Sdim  return true;
302275072Semaste}
303275072Semaste
304314564Sdimbool HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec) {
305314564Sdim  // TODO(zturner): Figure out how to compute the header directory for all
306314564Sdim  // platforms.
307314564Sdim  return false;
308275072Semaste}
309275072Semaste
310314564Sdimbool HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec) {
311314564Sdim  // TODO(zturner): Figure out how to compute the system plugins directory for
312314564Sdim  // all platforms.
313314564Sdim  return false;
314275072Semaste}
315275072Semaste
316314564Sdimbool HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) {
317341825Sdim  // TODO(zturner): Figure out how to compute the user plugins directory for
318341825Sdim  // all platforms.
319314564Sdim  return false;
320275072Semaste}
321275072Semaste
322314564Sdimvoid HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32,
323314564Sdim                                                  ArchSpec &arch_64) {
324314564Sdim  llvm::Triple triple(llvm::sys::getProcessTriple());
325275072Semaste
326314564Sdim  arch_32.Clear();
327314564Sdim  arch_64.Clear();
328275072Semaste
329314564Sdim  switch (triple.getArch()) {
330314564Sdim  default:
331314564Sdim    arch_32.SetTriple(triple);
332314564Sdim    break;
333275072Semaste
334314564Sdim  case llvm::Triple::aarch64:
335314564Sdim  case llvm::Triple::ppc64:
336341825Sdim  case llvm::Triple::ppc64le:
337314564Sdim  case llvm::Triple::x86_64:
338314564Sdim    arch_64.SetTriple(triple);
339314564Sdim    arch_32.SetTriple(triple.get32BitArchVariant());
340314564Sdim    break;
341275072Semaste
342314564Sdim  case llvm::Triple::mips64:
343314564Sdim  case llvm::Triple::mips64el:
344314564Sdim  case llvm::Triple::sparcv9:
345314564Sdim  case llvm::Triple::systemz:
346314564Sdim    arch_64.SetTriple(triple);
347314564Sdim    break;
348314564Sdim  }
349275072Semaste}
350