Tests updated so that they pass on both Linux and FreeBSD.

Hi kcc, samsonov,

http://llvm-reviews.chandlerc.com/D2644

CHANGE SINCE LAST DIFF
  http://llvm-reviews.chandlerc.com/D2644?vs=6987&id=7166#toc

Files:
  lib/Driver/SanitizerArgs.cpp
  lib/Driver/Tools.cpp
  test/Driver/freebsd-sanitizers.c
Index: lib/Driver/SanitizerArgs.cpp
===================================================================
--- lib/Driver/SanitizerArgs.cpp
+++ lib/Driver/SanitizerArgs.cpp
@@ -246,14 +246,15 @@
                                                const llvm::opt::Arg *A,
                                                bool DiagnoseErrors,
                                                unsigned &DiagnosedKinds) {
-  bool IsLinux = TC.getTriple().getOS() == llvm::Triple::Linux;
+  bool IsPosix = TC.getTriple().getOS() == llvm::Triple::Linux ||
+                 TC.getTriple().getOS() == llvm::Triple::FreeBSD;
   bool IsX86 = TC.getTriple().getArch() == llvm::Triple::x86;
   bool IsX86_64 = TC.getTriple().getArch() == llvm::Triple::x86_64;
-  if (!(IsLinux && IsX86_64)) {
+  if (!(IsPosix && IsX86_64)) {
     filterUnsupportedMask(TC, Kinds, Thread | Memory | DataFlow, Args, A,
                           DiagnoseErrors, DiagnosedKinds);
   }
-  if (!(IsLinux && (IsX86 || IsX86_64))) {
+  if (!(IsPosix && (IsX86 || IsX86_64))) {
     filterUnsupportedMask(TC, Kinds, Function, Args, A, DiagnoseErrors,
                           DiagnosedKinds);
   }
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -1901,6 +1901,53 @@
     addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "dfsan", true);
 }
 
+static void addProfileRTFreeBSD(
+    const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) {
+  if (!(Args.hasArg(options::OPT_fprofile_arcs) ||
+        Args.hasArg(options::OPT_fprofile_generate) ||
+        Args.hasArg(options::OPT_fcreate_profile) ||
+        Args.hasArg(options::OPT_coverage)))
+    return;
+
+  // The profile runtime is located in the freebsd library directory and has
+  // name "libclang_rt.profile-<ArchName>.a".
+  SmallString<128> LibProfile(TC.getDriver().ResourceDir);
+  llvm::sys::path::append(
+      LibProfile, "lib", "freebsd",
+      Twine("libclang_rt.profile-") + TC.getArchName() + ".a");
+
+  CmdArgs.push_back(Args.MakeArgString(LibProfile));
+}
+
+// Append a name of a appropriate Sanitizer library into a list
+// of the linker arguments.
+// This function returns true if an appropriate .syms file for
+// the specified Sanitizer library does exist and has been added into the linker
+// argument list to export the proper dynamic symbols;
+// otherwise this function returns false.
+static bool addSanitizerRTLinkFlagFreeBSD(
+    const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs,
+    const StringRef Sanitizer) {
+  // Sanitizer runtime is located in the freebsd library directory and
+  // has name "libclang_rt.<Sanitizer>-<ArchName>.a".
+  SmallString<128> LibSanitizer(TC.getDriver().ResourceDir);
+  llvm::sys::path::append(
+      LibSanitizer, "lib", "freebsd",
+      (Twine("libclang_rt.") + Sanitizer + "-" + TC.getArchName() + ".a"));
+
+  CmdArgs.push_back(Args.MakeArgString(LibSanitizer));
+
+  // If possible, use a dynamic symbols file to export the symbols from the
+  // runtime library. If we can't do so, use --export-dynamic instead to export
+  // all symbols from the binary.
+  const bool syms = llvm::sys::fs::exists(LibSanitizer + ".syms");
+  if (syms)
+    CmdArgs.push_back(
+        Args.MakeArgString("--dynamic-list=" + LibSanitizer + ".syms"));
+
+  return syms;
+}
+
 static bool shouldUseFramePointerForTarget(const ArgList &Args,
                                            const llvm::Triple &Triple) {
   switch (Triple.getArch()) {
@@ -5960,9 +6007,28 @@
                                  const InputInfoList &Inputs,
                                  const ArgList &Args,
                                  const char *LinkingOutput) const {
-  const toolchains::FreeBSD& ToolChain = 
+  const toolchains::FreeBSD &ToolChain =
     static_cast<const toolchains::FreeBSD&>(getToolChain());
   const Driver &D = ToolChain.getDriver();
+  const SanitizerArgs &Sanitize = ToolChain.getSanitizerArgs();
+  const bool IsPIE =
+    !Args.hasArg(options::OPT_shared) &&
+    (Args.hasArg(options::OPT_pie) || Sanitize.hasZeroBaseShadow());
+  const bool NeedsDefaultLibs =
+    !Args.hasArg(options::OPT_nostdlib) &&
+    !Args.hasArg(options::OPT_nodefaultlibs);
+  const bool NeedsCXXSanRt =
+    !Args.hasArg(options::OPT_shared) &&
+    (Sanitize.needsAsanRt() ||
+     Sanitize.needsTsanRt() ||
+     Sanitize.needsMsanRt() ||
+     Sanitize.needsLsanRt());
+  const bool NeedsUbsanRt = Sanitize.needsUbsanRt();
+  const bool NeedsSanRt = NeedsCXXSanRt || Sanitize.needsDfsanRt();
+  const bool NeedsCXXStdlib =
+    NeedsDefaultLibs &&
+    (D.CCCIsCXX() || NeedsUbsanRt);
+
   ArgStringList CmdArgs;
 
   // Silence warning for "clang -g foo.o -o foo"
@@ -5976,7 +6042,7 @@
   if (!D.SysRoot.empty())
     CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
 
-  if (Args.hasArg(options::OPT_pie))
+  if (IsPIE)
     CmdArgs.push_back("-pie");
 
   if (Args.hasArg(options::OPT_static)) {
@@ -6020,13 +6086,12 @@
     assert(Output.isNothing() && "Invalid output.");
   }
 
-  if (!Args.hasArg(options::OPT_nostdlib) &&
-      !Args.hasArg(options::OPT_nostartfiles)) {
+  if (NeedsDefaultLibs) {
     const char *crt1 = NULL;
     if (!Args.hasArg(options::OPT_shared)) {
       if (Args.hasArg(options::OPT_pg))
         crt1 = "gcrt1.o";
-      else if (Args.hasArg(options::OPT_pie))
+      else if (IsPIE)
         crt1 = "Scrt1.o";
       else
         crt1 = "crt1.o";
@@ -6039,7 +6104,7 @@
     const char *crtbegin = NULL;
     if (Args.hasArg(options::OPT_static))
       crtbegin = "crtbeginT.o";
-    else if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
+    else if (Args.hasArg(options::OPT_shared) || IsPIE)
       crtbegin = "crtbeginS.o";
     else
       crtbegin = "crtbegin.o";
@@ -6064,10 +6129,62 @@
 
   AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
 
-  if (!Args.hasArg(options::OPT_nostdlib) &&
-      !Args.hasArg(options::OPT_nodefaultlibs)) {
+  // Call these before we add the C++ ABI library.
+  // Sanitizer runtime may need to come before -lstdc++ (or -lc++, libstdc++.a,
+  // etc.) so that the linker picks custom versions of the global 'operator
+  // new' and 'operator delete' symbols. We take the extreme (but simple)
+  // strategy of inserting it at the front of the link command. It also
+  // needs to be forced to end up in the executable, so wrap it in
+  // whole-archive.
+  if (NeedsSanRt || NeedsUbsanRt) {
+    CmdArgs.push_back("-whole-archive");
+    if (NeedsUbsanRt) {
+      // Need a copy of sanitizer_common. This could come from another
+      // sanitizer runtime; if we're not including one, include our own copy.
+      if (!NeedsSanRt)
+        addSanitizerRTLinkFlagFreeBSD(ToolChain, Args, CmdArgs, "san");
+      addSanitizerRTLinkFlagFreeBSD(ToolChain, Args, CmdArgs, "ubsan");
+    }
+    bool NeedsExportDynamicOpt = false;
+    NeedsExportDynamicOpt |= (Sanitize.needsAsanRt() &&
+      !addSanitizerRTLinkFlagFreeBSD(ToolChain, Args, CmdArgs, "asan"));
+    NeedsExportDynamicOpt |= (Sanitize.needsTsanRt() &&
+      !addSanitizerRTLinkFlagFreeBSD(ToolChain, Args, CmdArgs, "tsan"));
+    NeedsExportDynamicOpt |= (Sanitize.needsMsanRt() &&
+      !addSanitizerRTLinkFlagFreeBSD(ToolChain, Args, CmdArgs, "msan"));
+    NeedsExportDynamicOpt |= (Sanitize.needsLsanRt() &&
+      !addSanitizerRTLinkFlagFreeBSD(ToolChain, Args, CmdArgs, "lsan"));
+    NeedsExportDynamicOpt |= (Sanitize.needsDfsanRt() &&
+      !addSanitizerRTLinkFlagFreeBSD(ToolChain, Args, CmdArgs, "dfsan"));
+
+    CmdArgs.push_back("-no-whole-archive");
+
+    // Force exporting of the dynamic symbols if it was not done before.
+    if (NeedsExportDynamicOpt &&
+        (!Args.hasArg(options::OPT_rdynamic) &&
+         !Args.hasArg(options::OPT_static)))
+      CmdArgs.push_back("--export-dynamic");
+
+    if (NeedsDefaultLibs)
+      CmdArgs.push_back("-lrt");
+  }
+
+  // The profile runtime also needs access to system libraries.
+  addProfileRTFreeBSD(ToolChain, Args, CmdArgs);
+
+  if (NeedsCXXStdlib)
+    ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+
+  if (NeedsUbsanRt && D.CCCIsCXX()) {
+    // Only include the bits of the runtime which need a C++ ABI library if
+    // we're linking in C++ mode.
+    CmdArgs.push_back("-whole-archive");
+    addSanitizerRTLinkFlagFreeBSD(ToolChain, Args, CmdArgs, "ubsan_cxx");
+    CmdArgs.push_back("-no-whole-archive");
+  }
+
+  if (NeedsDefaultLibs) {
     if (D.CCCIsCXX()) {
-      ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
       if (Args.hasArg(options::OPT_pg))
         CmdArgs.push_back("-lm_p");
       else
@@ -6089,7 +6206,7 @@
       CmdArgs.push_back("--no-as-needed");
     }
 
-    if (Args.hasArg(options::OPT_pthread)) {
+    if (Args.hasArg(options::OPT_pthread) || NeedsSanRt || NeedsUbsanRt) {
       if (Args.hasArg(options::OPT_pg))
         CmdArgs.push_back("-lpthread_p");
       else
@@ -6118,19 +6235,15 @@
     }
   }
 
-  if (!Args.hasArg(options::OPT_nostdlib) &&
-      !Args.hasArg(options::OPT_nostartfiles)) {
-    if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
+  if (NeedsDefaultLibs) {
+    if (Args.hasArg(options::OPT_shared) || IsPIE)
       CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o")));
     else
       CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
     CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
   }
 
-  addProfileRT(ToolChain, Args, CmdArgs, ToolChain.getTriple());
-
-  const char *Exec =
-    Args.MakeArgString(ToolChain.GetProgramPath("ld"));
+  const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld"));
   C.addCommand(new Command(JA, *this, Exec, CmdArgs));
 }
 
Index: test/Driver/freebsd-sanitizers.c
===================================================================
--- test/Driver/freebsd-sanitizers.c
+++ test/Driver/freebsd-sanitizers.c
@@ -0,0 +1,32 @@
+
+// RUN: %clang -no-canonical-prefixes -target i386-pc-freebsd \
+// RUN:     -fsanitize=address %s -### 2>&1 | \
+// RUN:   FileCheck --check-prefix=CHECK-ASAN-I386 %s
+// CHECK-ASAN-I386: "-whole-archive" "{{.*}}/lib/freebsd/libclang_rt.asan-i386.a"
+// CHECK-ASAN-I386: "--export-dynamic" "-lrt" "-lgcc"
+
+// RUN: %clang -no-canonical-prefixes -target x86_64-pc-freebsd \
+// RUN:     -fsanitize=address %s -### 2>&1 | \
+// RUN:   FileCheck --check-prefix=CHECK-ASAN-X86_64 %s
+// CHECK-ASAN-X86_64: "-whole-archive" "{{.*}}/lib/freebsd/libclang_rt.asan-x86_64.a"
+// CHECK-ASAN-X86_64: "-lrt" "-lgcc"
+
+// RUN: %clang -no-canonical-prefixes -target i386-pc-freebsd \
+// RUN:     -fsanitize=undefined %s -### 2>&1 | \
+// RUN:   FileCheck --check-prefix=CHECK-UBSAN-I386 %s
+// CHECK-UBSAN-I386: "-whole-archive" "{{.*}}/freebsd/libclang_rt.san-i386.a" "{{.*}}/freebsd/libclang_rt.ubsan-i386.a"
+// CHECK-UBSAN-I386: "-lrt" "-lstdc++"
+
+// RUN: %clang -no-canonical-prefixes -target x86_64-pc-freebsd \
+// RUN:     -fsanitize=undefined %s -### 2>&1 | \
+// RUN:   FileCheck --check-prefix=CHECK-UBSAN-X86_64 %s
+// CHECK-UBSAN-X86_64: "-whole-archive" "{{.*}}/freebsd/libclang_rt.san-x86_64.a" "{{.*}}/freebsd/libclang_rt.ubsan-x86_64.a"
+// CHECK-UBSAN-X86_64: "-lrt" "-lstdc++"
+// CHECK-UBSAN-X86_64-NOT: libclang_rt.ubsan_cxx
+
+// RUN: %clangxx -no-canonical-prefixes -target x86_64-pc-freebsd \
+// RUN:     -fsanitize=undefined %s -### 2>&1 | \
+// RUN:   FileCheck --check-prefix=CHECK-UBSAN-CXX %s
+// CHECK-UBSAN-CXX: "-whole-archive" "{{.*}}/freebsd/libclang_rt.san-x86_64.a" "{{.*}}/freebsd/libclang_rt.ubsan-x86_64.a"
+// CHECK-UBSAN-CXX: "-lrt" "-lstdc++"
+// CHECK-UBSAN-CXX: "-whole-archive" "{{.*}}/freebsd/libclang_rt.ubsan_cxx-x86_64.a"
_______________________________________________
cfe-commits mailing list
cfe-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to