Coverage Report

Created: 2022-01-18 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- Fuchsia.cpp - Fuchsia ToolChain Implementations --------*- C++ -*-===//
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 "Fuchsia.h"
10
#include "CommonArgs.h"
11
#include "clang/Config/config.h"
12
#include "clang/Driver/Compilation.h"
13
#include "clang/Driver/Driver.h"
14
#include "clang/Driver/DriverDiagnostic.h"
15
#include "clang/Driver/Options.h"
16
#include "clang/Driver/SanitizerArgs.h"
17
#include "llvm/Option/ArgList.h"
18
#include "llvm/ProfileData/InstrProf.h"
19
#include "llvm/Support/FileSystem.h"
20
#include "llvm/Support/Path.h"
21
#include "llvm/Support/VirtualFileSystem.h"
22
23
using namespace clang::driver;
24
using namespace clang::driver::toolchains;
25
using namespace clang::driver::tools;
26
using namespace clang;
27
using namespace llvm::opt;
28
29
using tools::addMultilibFlag;
30
31
void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,
32
                                   const InputInfo &Output,
33
                                   const InputInfoList &Inputs,
34
                                   const ArgList &Args,
35
59
                                   const char *LinkingOutput) const {
36
59
  const toolchains::Fuchsia &ToolChain =
37
59
      static_cast<const toolchains::Fuchsia &>(getToolChain());
38
59
  const Driver &D = ToolChain.getDriver();
39
40
59
  ArgStringList CmdArgs;
41
42
  // Silence warning for "clang -g foo.o -o foo"
43
59
  Args.ClaimAllArgs(options::OPT_g_Group);
44
  // and "clang -emit-llvm foo.o -o foo"
45
59
  Args.ClaimAllArgs(options::OPT_emit_llvm);
46
  // and for "clang -w foo.o -o foo". Other warning options are already
47
  // handled somewhere else.
48
59
  Args.ClaimAllArgs(options::OPT_w);
49
50
59
  CmdArgs.push_back("-z");
51
59
  CmdArgs.push_back("max-page-size=4096");
52
53
59
  CmdArgs.push_back("-z");
54
59
  CmdArgs.push_back("now");
55
56
59
  const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
57
59
  if (llvm::sys::path::filename(Exec).equals_insensitive("ld.lld") ||
58
59
      
llvm::sys::path::stem(Exec).equals_insensitive("ld.lld")0
) {
59
59
    CmdArgs.push_back("-z");
60
59
    CmdArgs.push_back("rodynamic");
61
59
    CmdArgs.push_back("-z");
62
59
    CmdArgs.push_back("separate-loadable-segments");
63
59
    CmdArgs.push_back("-z");
64
59
    CmdArgs.push_back("rel");
65
59
    CmdArgs.push_back("--pack-dyn-relocs=relr");
66
59
  }
67
68
59
  if (!D.SysRoot.empty())
69
12
    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
70
71
59
  if (!Args.hasArg(options::OPT_shared) && 
!Args.hasArg(options::OPT_r)55
)
72
54
    CmdArgs.push_back("-pie");
73
74
59
  if (Args.hasArg(options::OPT_rdynamic))
75
0
    CmdArgs.push_back("-export-dynamic");
76
77
59
  if (Args.hasArg(options::OPT_s))
78
0
    CmdArgs.push_back("-s");
79
80
59
  if (Args.hasArg(options::OPT_r)) {
81
1
    CmdArgs.push_back("-r");
82
58
  } else {
83
58
    CmdArgs.push_back("--build-id");
84
58
    CmdArgs.push_back("--hash-style=gnu");
85
58
  }
86
87
59
  CmdArgs.push_back("--eh-frame-hdr");
88
89
59
  if (Args.hasArg(options::OPT_static))
90
1
    CmdArgs.push_back("-Bstatic");
91
58
  else if (Args.hasArg(options::OPT_shared))
92
4
    CmdArgs.push_back("-shared");
93
94
59
  const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs(Args);
95
96
59
  if (!Args.hasArg(options::OPT_shared)) {
97
55
    std::string Dyld = D.DyldPrefix;
98
55
    if (SanArgs.needsAsanRt() && 
SanArgs.needsSharedRt()6
)
99
6
      Dyld += "asan/";
100
55
    if (SanArgs.needsHwasanRt() && 
SanArgs.needsSharedRt()4
)
101
4
      Dyld += "hwasan/";
102
55
    if (SanArgs.needsTsanRt() && 
SanArgs.needsSharedRt()0
)
103
0
      Dyld += "tsan/";
104
55
    Dyld += "ld.so.1";
105
55
    CmdArgs.push_back("-dynamic-linker");
106
55
    CmdArgs.push_back(Args.MakeArgString(Dyld));
107
55
  }
108
109
59
  CmdArgs.push_back("-o");
110
59
  CmdArgs.push_back(Output.getFilename());
111
112
59
  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
113
59
                   options::OPT_r)) {
114
57
    if (!Args.hasArg(options::OPT_shared)) {
115
53
      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("Scrt1.o")));
116
53
    }
117
57
  }
118
119
59
  Args.AddAllArgs(CmdArgs, options::OPT_L);
120
59
  Args.AddAllArgs(CmdArgs, options::OPT_u);
121
122
59
  ToolChain.AddFilePathLibArgs(Args, CmdArgs);
123
124
59
  if (D.isUsingLTO()) {
125
2
    assert(!Inputs.empty() && "Must have at least one input.");
126
0
    addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0],
127
2
                  D.getLTOMode() == LTOK_Thin);
128
2
  }
129
130
0
  bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
131
59
  bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs);
132
59
  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
133
59
  ToolChain.addProfileRTLibs(Args, CmdArgs);
134
135
59
  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,
136
59
                   options::OPT_r)) {
137
56
    if (Args.hasArg(options::OPT_static))
138
1
      CmdArgs.push_back("-Bdynamic");
139
140
56
    if (D.CCCIsCXX()) {
141
27
      if (ToolChain.ShouldLinkCXXStdlib(Args)) {
142
26
        bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
143
26
                                   
!Args.hasArg(options::OPT_static)1
;
144
26
        CmdArgs.push_back("--push-state");
145
26
        CmdArgs.push_back("--as-needed");
146
26
        if (OnlyLibstdcxxStatic)
147
1
          CmdArgs.push_back("-Bstatic");
148
26
        ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
149
26
        if (OnlyLibstdcxxStatic)
150
1
          CmdArgs.push_back("-Bdynamic");
151
26
        CmdArgs.push_back("-lm");
152
26
        CmdArgs.push_back("--pop-state");
153
26
      }
154
27
    }
155
156
56
    if (NeedsSanitizerDeps)
157
2
      linkSanitizerRuntimeDeps(ToolChain, CmdArgs);
158
159
56
    if (NeedsXRayDeps)
160
2
      linkXRayRuntimeDeps(ToolChain, CmdArgs);
161
162
56
    AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
163
164
56
    if (Args.hasArg(options::OPT_pthread) ||
165
56
        Args.hasArg(options::OPT_pthreads))
166
0
      CmdArgs.push_back("-lpthread");
167
168
56
    if (Args.hasArg(options::OPT_fsplit_stack))
169
0
      CmdArgs.push_back("--wrap=pthread_create");
170
171
56
    if (!Args.hasArg(options::OPT_nolibc))
172
55
      CmdArgs.push_back("-lc");
173
56
  }
174
175
59
  C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
176
59
                                         Exec, CmdArgs, Inputs, Output));
177
59
}
178
179
/// Fuchsia - Fuchsia tool chain which can call as(1) and ld(1) directly.
180
181
Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple,
182
                 const ArgList &Args)
183
68
    : ToolChain(D, Triple, Args) {
184
68
  getProgramPaths().push_back(getDriver().getInstalledDir());
185
68
  if (getDriver().getInstalledDir() != D.Dir)
186
0
    getProgramPaths().push_back(D.Dir);
187
188
68
  if (!D.SysRoot.empty()) {
189
12
    SmallString<128> P(D.SysRoot);
190
12
    llvm::sys::path::append(P, "lib");
191
12
    getFilePaths().push_back(std::string(P.str()));
192
12
  }
193
194
898
  auto FilePaths = [&](const Multilib &M) -> std::vector<std::string> {
195
898
    std::vector<std::string> FP;
196
898
    for (const std::string &Path : getStdlibPaths()) {
197
898
      SmallString<128> P(Path);
198
898
      llvm::sys::path::append(P, M.gccSuffix());
199
898
      FP.push_back(std::string(P.str()));
200
898
    }
201
898
    return FP;
202
898
  };
203
204
68
  Multilibs.push_back(Multilib());
205
  // Use the noexcept variant with -fno-exceptions to avoid the extra overhead.
206
68
  Multilibs.push_back(Multilib("noexcept", {}, {}, 1)
207
68
                          .flag("-fexceptions")
208
68
                          .flag("+fno-exceptions"));
209
  // ASan has higher priority because we always want the instrumentated version.
210
68
  Multilibs.push_back(Multilib("asan", {}, {}, 2)
211
68
                          .flag("+fsanitize=address"));
212
  // Use the asan+noexcept variant with ASan and -fno-exceptions.
213
68
  Multilibs.push_back(Multilib("asan+noexcept", {}, {}, 3)
214
68
                          .flag("+fsanitize=address")
215
68
                          .flag("-fexceptions")
216
68
                          .flag("+fno-exceptions"));
217
  // HWASan has higher priority because we always want the instrumentated
218
  // version.
219
68
  Multilibs.push_back(
220
68
      Multilib("hwasan", {}, {}, 4).flag("+fsanitize=hwaddress"));
221
  // Use the hwasan+noexcept variant with HWASan and -fno-exceptions.
222
68
  Multilibs.push_back(Multilib("hwasan+noexcept", {}, {}, 5)
223
68
                          .flag("+fsanitize=hwaddress")
224
68
                          .flag("-fexceptions")
225
68
                          .flag("+fno-exceptions"));
226
  // Use the relative vtables ABI.
227
  // TODO: Remove these multilibs once relative vtables are enabled by default
228
  // for Fuchsia.
229
68
  Multilibs.push_back(Multilib("relative-vtables", {}, {}, 6)
230
68
                          .flag("+fexperimental-relative-c++-abi-vtables"));
231
68
  Multilibs.push_back(Multilib("relative-vtables+noexcept", {}, {}, 7)
232
68
                          .flag("+fexperimental-relative-c++-abi-vtables")
233
68
                          .flag("-fexceptions")
234
68
                          .flag("+fno-exceptions"));
235
68
  Multilibs.push_back(Multilib("relative-vtables+asan", {}, {}, 8)
236
68
                          .flag("+fexperimental-relative-c++-abi-vtables")
237
68
                          .flag("+fsanitize=address"));
238
68
  Multilibs.push_back(Multilib("relative-vtables+asan+noexcept", {}, {}, 9)
239
68
                          .flag("+fexperimental-relative-c++-abi-vtables")
240
68
                          .flag("+fsanitize=address")
241
68
                          .flag("-fexceptions")
242
68
                          .flag("+fno-exceptions"));
243
68
  Multilibs.push_back(Multilib("relative-vtables+hwasan", {}, {}, 10)
244
68
                          .flag("+fexperimental-relative-c++-abi-vtables")
245
68
                          .flag("+fsanitize=hwaddress"));
246
68
  Multilibs.push_back(Multilib("relative-vtables+hwasan+noexcept", {}, {}, 11)
247
68
                          .flag("+fexperimental-relative-c++-abi-vtables")
248
68
                          .flag("+fsanitize=hwaddress")
249
68
                          .flag("-fexceptions")
250
68
                          .flag("+fno-exceptions"));
251
  // Use Itanium C++ ABI for the compat multilib.
252
68
  Multilibs.push_back(Multilib("compat", {}, {}, 12).flag("+fc++-abi=itanium"));
253
254
884
  Multilibs.FilterOut([&](const Multilib &M) {
255
884
    std::vector<std::string> RD = FilePaths(M);
256
884
    return llvm::all_of(RD, [&](std::string P) { return !getVFS().exists(P); });
257
884
  });
258
259
68
  Multilib::flags_list Flags;
260
68
  addMultilibFlag(
261
68
      Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, true),
262
68
      "fexceptions", Flags);
263
68
  addMultilibFlag(getSanitizerArgs(Args).needsAsanRt(), "fsanitize=address",
264
68
                  Flags);
265
68
  addMultilibFlag(getSanitizerArgs(Args).needsHwasanRt(), "fsanitize=hwaddress",
266
68
                  Flags);
267
268
68
  addMultilibFlag(
269
68
      Args.hasFlag(options::OPT_fexperimental_relative_cxx_abi_vtables,
270
68
                   options::OPT_fno_experimental_relative_cxx_abi_vtables,
271
68
                   /*default=*/false),
272
68
      "fexperimental-relative-c++-abi-vtables", Flags);
273
68
  addMultilibFlag(Args.getLastArgValue(options::OPT_fcxx_abi_EQ) == "itanium",
274
68
                  "fc++-abi=itanium", Flags);
275
276
68
  Multilibs.setFilePathsCallback(FilePaths);
277
278
68
  if (Multilibs.select(Flags, SelectedMultilib))
279
22
    if (!SelectedMultilib.isDefault())
280
14
      if (const auto &PathsCallback = Multilibs.filePathsCallback())
281
14
        for (const auto &Path : PathsCallback(SelectedMultilib))
282
          // Prepend the multilib path to ensure it takes the precedence.
283
14
          getFilePaths().insert(getFilePaths().begin(), Path);
284
68
}
285
286
std::string Fuchsia::ComputeEffectiveClangTriple(const ArgList &Args,
287
128
                                                 types::ID InputType) const {
288
128
  llvm::Triple Triple(ComputeLLVMTriple(Args, InputType));
289
128
  return Triple.str();
290
128
}
291
292
59
Tool *Fuchsia::buildLinker() const {
293
59
  return new tools::fuchsia::Linker(*this);
294
59
}
295
296
ToolChain::RuntimeLibType Fuchsia::GetRuntimeLibType(
297
112
    const ArgList &Args) const {
298
112
  if (Arg *A = Args.getLastArg(clang::driver::options::OPT_rtlib_EQ)) {
299
2
    StringRef Value = A->getValue();
300
2
    if (Value != "compiler-rt")
301
2
      getDriver().Diag(clang::diag::err_drv_invalid_rtlib_name)
302
2
          << A->getAsString(Args);
303
2
  }
304
305
112
  return ToolChain::RLT_CompilerRT;
306
112
}
307
308
ToolChain::CXXStdlibType
309
59
Fuchsia::GetCXXStdlibType(const ArgList &Args) const {
310
59
  if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) {
311
2
    StringRef Value = A->getValue();
312
2
    if (Value != "libc++")
313
2
      getDriver().Diag(diag::err_drv_invalid_stdlib_name)
314
2
        << A->getAsString(Args);
315
2
  }
316
317
59
  return ToolChain::CST_Libcxx;
318
59
}
319
320
void Fuchsia::addClangTargetOptions(const ArgList &DriverArgs,
321
                                    ArgStringList &CC1Args,
322
69
                                    Action::OffloadKind) const {
323
69
  if (!DriverArgs.hasFlag(options::OPT_fuse_init_array,
324
69
                          options::OPT_fno_use_init_array, true))
325
0
    CC1Args.push_back("-fno-use-init-array");
326
69
}
327
328
void Fuchsia::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
329
69
                                        ArgStringList &CC1Args) const {
330
69
  const Driver &D = getDriver();
331
332
69
  if (DriverArgs.hasArg(options::OPT_nostdinc))
333
0
    return;
334
335
69
  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
336
69
    SmallString<128> P(D.ResourceDir);
337
69
    llvm::sys::path::append(P, "include");
338
69
    addSystemInclude(DriverArgs, CC1Args, P);
339
69
  }
340
341
69
  if (DriverArgs.hasArg(options::OPT_nostdlibinc))
342
0
    return;
343
344
  // Check for configure-time C include directories.
345
69
  StringRef CIncludeDirs(C_INCLUDE_DIRS);
346
69
  if (CIncludeDirs != "") {
347
0
    SmallVector<StringRef, 5> dirs;
348
0
    CIncludeDirs.split(dirs, ":");
349
0
    for (StringRef dir : dirs) {
350
0
      StringRef Prefix =
351
0
          llvm::sys::path::is_absolute(dir) ? "" : StringRef(D.SysRoot);
352
0
      addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
353
0
    }
354
0
    return;
355
0
  }
356
357
69
  if (!D.SysRoot.empty()) {
358
12
    SmallString<128> P(D.SysRoot);
359
12
    llvm::sys::path::append(P, "include");
360
12
    addExternCSystemInclude(DriverArgs, CC1Args, P.str());
361
12
  }
362
69
}
363
364
void Fuchsia::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
365
31
                                           ArgStringList &CC1Args) const {
366
31
  if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
367
31
      DriverArgs.hasArg(options::OPT_nostdincxx))
368
0
    return;
369
370
31
  const Driver &D = getDriver();
371
31
  std::string Target = getTripleString();
372
373
31
  auto AddCXXIncludePath = [&](StringRef Path) {
374
31
    std::string Version = detectLibcxxVersion(Path);
375
31
    if (Version.empty())
376
0
      return;
377
378
    // First add the per-target include path.
379
31
    SmallString<128> TargetDir(Path);
380
31
    llvm::sys::path::append(TargetDir, Target, "c++", Version);
381
31
    if (getVFS().exists(TargetDir))
382
24
      addSystemInclude(DriverArgs, CC1Args, TargetDir);
383
384
    // Second add the generic one.
385
31
    SmallString<128> Dir(Path);
386
31
    llvm::sys::path::append(Dir, "c++", Version);
387
31
    addSystemInclude(DriverArgs, CC1Args, Dir);
388
31
  };
389
390
31
  switch (GetCXXStdlibType(DriverArgs)) {
391
31
  case ToolChain::CST_Libcxx: {
392
31
    SmallString<128> P(D.Dir);
393
31
    llvm::sys::path::append(P, "..", "include");
394
31
    AddCXXIncludePath(P);
395
31
    break;
396
0
  }
397
398
0
  default:
399
0
    llvm_unreachable("invalid stdlib name");
400
31
  }
401
31
}
402
403
void Fuchsia::AddCXXStdlibLibArgs(const ArgList &Args,
404
28
                                  ArgStringList &CmdArgs) const {
405
28
  switch (GetCXXStdlibType(Args)) {
406
28
  case ToolChain::CST_Libcxx:
407
28
    CmdArgs.push_back("-lc++");
408
28
    break;
409
410
0
  case ToolChain::CST_Libstdcxx:
411
0
    llvm_unreachable("invalid stdlib name");
412
28
  }
413
28
}
414
415
382
SanitizerMask Fuchsia::getSupportedSanitizers() const {
416
382
  SanitizerMask Res = ToolChain::getSupportedSanitizers();
417
382
  Res |= SanitizerKind::Address;
418
382
  Res |= SanitizerKind::HWAddress;
419
382
  Res |= SanitizerKind::PointerCompare;
420
382
  Res |= SanitizerKind::PointerSubtract;
421
382
  Res |= SanitizerKind::Fuzzer;
422
382
  Res |= SanitizerKind::FuzzerNoLink;
423
382
  Res |= SanitizerKind::Leak;
424
382
  Res |= SanitizerKind::SafeStack;
425
382
  Res |= SanitizerKind::Scudo;
426
382
  Res |= SanitizerKind::Thread;
427
382
  return Res;
428
382
}
429
430
382
SanitizerMask Fuchsia::getDefaultSanitizers() const {
431
382
  SanitizerMask Res;
432
382
  switch (getTriple().getArch()) {
433
81
  case llvm::Triple::aarch64:
434
81
    Res |= SanitizerKind::ShadowCallStack;
435
81
    break;
436
277
  case llvm::Triple::x86_64:
437
277
    Res |= SanitizerKind::SafeStack;
438
277
    break;
439
24
  default:
440
    // TODO: Enable SafeStack on RISC-V once tested.
441
24
    break;
442
382
  }
443
382
  return Res;
444
382
}