Coverage Report

Created: 2022-01-18 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- ClangHost.cpp -----------------------------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "ClangHost.h"
10
11
#include "clang/Basic/Version.h"
12
#include "clang/Config/config.h"
13
14
#include "llvm/ADT/StringRef.h"
15
#include "llvm/ADT/Twine.h"
16
#include "llvm/Support/FileSystem.h"
17
#include "llvm/Support/Threading.h"
18
19
#include "lldb/Host/Config.h"
20
#include "lldb/Host/FileSystem.h"
21
#include "lldb/Host/HostInfo.h"
22
#include "lldb/Utility/FileSpec.h"
23
#include "lldb/Utility/Log.h"
24
25
#include <string>
26
27
using namespace lldb_private;
28
29
472
static bool VerifyClangPath(const llvm::Twine &clang_path) {
30
472
  if (FileSystem::Instance().IsDirectory(clang_path))
31
451
    return true;
32
21
  Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
33
21
  LLDB_LOGF(log,
34
21
            "VerifyClangPath(): "
35
21
            "failed to stat clang resource directory at \"%s\"",
36
21
            clang_path.str().c_str());
37
21
  return false;
38
472
}
39
40
///
41
/// This will compute the clang resource directory assuming that clang was
42
/// installed with the same prefix as lldb.
43
///
44
/// If verify is true, the first candidate resource directory will be returned.
45
/// This mode is only used for testing.
46
///
47
static bool DefaultComputeClangResourceDirectory(FileSpec &lldb_shlib_spec,
48
                                                 FileSpec &file_spec,
49
463
                                                 bool verify) {
50
463
  Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
51
463
  std::string raw_path = lldb_shlib_spec.GetPath();
52
463
  llvm::StringRef parent_dir = llvm::sys::path::parent_path(raw_path);
53
54
463
  static const llvm::StringRef kResourceDirSuffixes[] = {
55
      // LLVM.org's build of LLDB uses the clang resource directory placed
56
      // in $install_dir/lib{,64}/clang/$clang_version.
57
463
      "lib" CLANG_LIBDIR_SUFFIX "/clang/" CLANG_VERSION_STRING,
58
      // swift-lldb uses the clang resource directory copied from swift, which
59
      // by default is placed in $install_dir/lib{,64}/lldb/clang. LLDB places
60
      // it there, so we use LLDB_LIBDIR_SUFFIX.
61
463
      "lib" LLDB_LIBDIR_SUFFIX "/lldb/clang",
62
463
  };
63
64
473
  for (const auto &Suffix : kResourceDirSuffixes) {
65
473
    llvm::SmallString<256> clang_dir(parent_dir);
66
473
    llvm::SmallString<32> relative_path(Suffix);
67
473
    llvm::sys::path::native(relative_path);
68
473
    llvm::sys::path::append(clang_dir, relative_path);
69
473
    if (!verify || 
VerifyClangPath(clang_dir)471
) {
70
453
      LLDB_LOG(log,
71
453
               "DefaultComputeClangResourceDir: Setting ClangResourceDir "
72
453
               "to \"{0}\", verify = {1}",
73
453
               clang_dir.str(), verify ? "true" : "false");
74
453
      file_spec.GetDirectory().SetString(clang_dir);
75
453
      FileSystem::Instance().Resolve(file_spec);
76
453
      return true;
77
453
    }
78
473
  }
79
80
10
  return false;
81
463
}
82
83
bool lldb_private::ComputeClangResourceDirectory(FileSpec &lldb_shlib_spec,
84
469
                                         FileSpec &file_spec, bool verify) {
85
#if !defined(__APPLE__)
86
  return DefaultComputeClangResourceDirectory(lldb_shlib_spec, file_spec,
87
                                              verify);
88
#else
89
469
  std::string raw_path = lldb_shlib_spec.GetPath();
90
91
469
  auto rev_it = llvm::sys::path::rbegin(raw_path);
92
469
  auto r_end = llvm::sys::path::rend(raw_path);
93
94
  // Check for a Posix-style build of LLDB.
95
4.19k
  while (rev_it != r_end) {
96
3.73k
    if (*rev_it == "LLDB.framework")
97
6
      break;
98
3.72k
    ++rev_it;
99
3.72k
  }
100
101
  // We found a non-framework build of LLDB
102
469
  if (rev_it == r_end)
103
463
    return DefaultComputeClangResourceDirectory(lldb_shlib_spec, file_spec,
104
463
                                                verify);
105
106
  // Inside Xcode and in Xcode toolchains LLDB is always in lockstep
107
  // with the Swift compiler, so it can reuse its Clang resource
108
  // directory. This allows LLDB and the Swift compiler to share the
109
  // same Clang module cache.
110
6
  llvm::SmallString<256> clang_path;
111
6
  const char *swift_clang_resource_dir = "usr/lib/swift/clang";
112
6
  auto parent = std::next(rev_it);
113
6
  if (parent != r_end && *parent == "SharedFrameworks") {
114
    // This is the top-level LLDB in the Xcode.app bundle.
115
    // E.g., "Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/A"
116
3
    raw_path.resize(parent - r_end);
117
3
    llvm::sys::path::append(clang_path, raw_path,
118
3
                            "Developer/Toolchains/XcodeDefault.xctoolchain",
119
3
                            swift_clang_resource_dir);
120
3
    if (!verify || 
VerifyClangPath(clang_path)1
) {
121
2
      file_spec.GetDirectory().SetString(clang_path.c_str());
122
2
      FileSystem::Instance().Resolve(file_spec);
123
2
      return true;
124
2
    }
125
3
  } else if (parent != r_end && *parent == "PrivateFrameworks" &&
126
3
             
std::distance(parent, r_end) > 22
) {
127
2
    ++parent;
128
2
    ++parent;
129
2
    if (*parent == "System") {
130
      // This is LLDB inside an Xcode toolchain.
131
      // E.g., "Xcode.app/Contents/Developer/Toolchains/"               \
132
      //       "My.xctoolchain/System/Library/PrivateFrameworks/LLDB.framework"
133
1
      raw_path.resize(parent - r_end);
134
1
      llvm::sys::path::append(clang_path, raw_path, swift_clang_resource_dir);
135
1
      if (!verify || 
VerifyClangPath(clang_path)0
) {
136
1
        file_spec.GetDirectory().SetString(clang_path.c_str());
137
1
        FileSystem::Instance().Resolve(file_spec);
138
1
        return true;
139
1
      }
140
1
    }
141
2
  }
142
143
  // Fall back to the Clang resource directory inside the framework.
144
3
  raw_path = lldb_shlib_spec.GetPath();
145
3
  raw_path.resize(rev_it - r_end);
146
3
  raw_path.append("LLDB.framework/Resources/Clang");
147
3
  file_spec.GetDirectory().SetString(raw_path.c_str());
148
3
  FileSystem::Instance().Resolve(file_spec);
149
3
  return true;
150
6
#endif // __APPLE__
151
6
}
152
153
3.02k
FileSpec lldb_private::GetClangResourceDir() {
154
3.02k
  static FileSpec g_cached_resource_dir;
155
3.02k
  static llvm::once_flag g_once_flag;
156
3.02k
  llvm::call_once(g_once_flag, []() {
157
460
    if (FileSpec lldb_file_spec = HostInfo::GetShlibDir())
158
460
      ComputeClangResourceDirectory(lldb_file_spec, g_cached_resource_dir,
159
460
                                    true);
160
460
    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
161
460
    LLDB_LOGF(log, "GetClangResourceDir() => '%s'",
162
460
              g_cached_resource_dir.GetPath().c_str());
163
460
  });
164
3.02k
  return g_cached_resource_dir;
165
3.02k
}