Merge "Add linkerconfig to the host exports."
diff --git a/build/coverage.sh b/build/coverage.sh
new file mode 100644
index 0000000..5f305ce
--- /dev/null
+++ b/build/coverage.sh
@@ -0,0 +1,47 @@
+#!/bin/bash
+
+# This script generates coverage for bionic.
+#
+# Prereqs: Coverage-enabled build.
+#   $ lunch <target>
+#   $ m NATIVE_COVERAGE_PATHS="bionic" CLANG_COVERAGE=true
+#   $ m NATIVE_COVERAGE_PATHS="bionic" CLANG_COVERAGE=true bionic-unit-tests
+# Flash image and set $ANDROID_SERIAL
+#
+# Usage: $ bionic/build/coverage.sh
+# Output: HTML report is generated to /tmp/bionic-coverage/html/index.html
+#
+
+eval "$(cd ${ANDROID_BUILD_TOP}; build/soong/soong_ui.bash --dumpvars-mode --vars="TARGET_ARCH")"
+
+LLVM_PROFDATA=${ANDROID_BUILD_TOP}/prebuilts/clang/host/linux-x86/llvm-binutils-stable/llvm-profdata
+LLVM_COV=${ANDROID_BUILD_TOP}/prebuilts/clang/host/linux-x86/llvm-binutils-stable/llvm-cov
+
+DEVICE_TEST_DIR=/data/local/tmp/bionic-coverage
+HOST_PROFDATA_DIR=/tmp/bionic-coverage
+
+# Run bionic-unit-tests
+adb shell rm -rf ${DEVICE_TEST_DIR}
+adb shell mkdir ${DEVICE_TEST_DIR}
+adb push $OUT/data/nativetest/bionic-loader-test-libs ${DEVICE_TEST_DIR}
+adb push $OUT/data/nativetest/bionic-unit-tests ${DEVICE_TEST_DIR}
+adb shell LLVM_PROFILE_FILE=${DEVICE_TEST_DIR}/profraws/bionic-%p-%m.profraw LD_LIBRARY_PATH=${DEVICE_TEST_DIR}/bionic-loader-test-libs ${DEVICE_TEST_DIR}/bionic-unit-tests/bionic-unit-tests
+
+# Pull coverage files and post-process
+rm -rf ${HOST_PROFDATA_DIR}
+mkdir ${HOST_PROFDATA_DIR}
+adb pull ${DEVICE_TEST_DIR}/profraws ${HOST_PROFDATA_DIR}/profraws
+
+
+${LLVM_PROFDATA} merge \
+  --output=${HOST_PROFDATA_DIR}/bionic.profdata \
+  ${HOST_PROFDATA_DIR}/profraws/*.profraw
+
+${LLVM_COV} show \
+  --instr-profile=${HOST_PROFDATA_DIR}/bionic.profdata \
+  --format=html \
+  out/soong/.intermediates/bionic/libc/libc/android_${TARGET_ARCH}_shared_cov/unstripped/libc.so \
+  --object=out/soong/.intermediates/bionic/tests/bionic-unit-tests/android_${TARGET_ARCH}_cov/unstripped/bionic-unit-tests \
+  /proc/self/cwd/bionic/libc \
+  --output-dir=${HOST_PROFDATA_DIR}/html \
+  --show-region-summary=false
diff --git a/libc/Android.bp b/libc/Android.bp
index 6340340..5bd00c8 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -81,7 +81,6 @@
         // TODO(b/132640749): Fix broken fuzzer support.
         fuzzer: false,
     },
-    native_coverage: false,
     ramdisk_available: true,
     recovery_available: true,
     native_bridge_supported: true,
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index c427282..fcf4497 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -1268,6 +1268,7 @@
     name: "libtest_check_rtld_next_from_library",
     defaults: ["bionic_testlib_defaults"],
     srcs: ["check_rtld_next_from_library.cpp"],
+    native_coverage: false,
 }
 
 // -----------------------------------------------------------------------------
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 6b28561..43d50f8 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -1350,6 +1350,11 @@
   ASSERT_EQ(EACCES, errno);
 }
 
+static void append_llvm_cov_env_var(std::string& env_str) {
+  if (getenv("LLVM_PROFILE_FILE") != nullptr)
+    env_str.append("__LLVM_PROFILE_RT_INIT_ONCE=__LLVM_PROFILE_RT_INIT_ONCE\n");
+}
+
 TEST(UNISTD_TEST, execve_args) {
   // int execve(const char* path, char* argv[], char* envp[]);
 
@@ -1361,7 +1366,12 @@
   // Test environment variable setting too.
   eth.SetArgs({"printenv", nullptr});
   eth.SetEnv({"A=B", nullptr});
-  eth.Run([&]() { execve(BIN_DIR "printenv", eth.GetArgs(), eth.GetEnv()); }, 0, "A=B\n");
+
+  std::string expected_output("A=B\n");
+  append_llvm_cov_env_var(expected_output);
+
+  eth.Run([&]() { execve(BIN_DIR "printenv", eth.GetArgs(), eth.GetEnv()); }, 0,
+          expected_output.c_str());
 }
 
 TEST(UNISTD_TEST, execl_failure) {
@@ -1386,8 +1396,13 @@
 TEST(UNISTD_TEST, execle) {
   ExecTestHelper eth;
   eth.SetEnv({"A=B", nullptr});
+
+  std::string expected_output("A=B\n");
+  append_llvm_cov_env_var(expected_output);
+
   // int execle(const char* path, const char* arg, ..., char* envp[]);
-  eth.Run([&]() { execle(BIN_DIR "printenv", "printenv", nullptr, eth.GetEnv()); }, 0, "A=B\n");
+  eth.Run([&]() { execle(BIN_DIR "printenv", "printenv", nullptr, eth.GetEnv()); }, 0,
+          expected_output.c_str());
 }
 
 TEST(UNISTD_TEST, execv_failure) {
@@ -1450,7 +1465,11 @@
   // Test environment variable setting too.
   eth.SetArgs({"printenv", nullptr});
   eth.SetEnv({"A=B", nullptr});
-  eth.Run([&]() { execvpe("printenv", eth.GetArgs(), eth.GetEnv()); }, 0, "A=B\n");
+
+  std::string expected_output("A=B\n");
+  append_llvm_cov_env_var(expected_output);
+
+  eth.Run([&]() { execvpe("printenv", eth.GetArgs(), eth.GetEnv()); }, 0, expected_output.c_str());
 }
 
 TEST(UNISTD_TEST, execvpe_ENOEXEC) {
@@ -1538,7 +1557,11 @@
   ASSERT_NE(-1, printenv_fd);
   eth.SetArgs({"printenv", nullptr});
   eth.SetEnv({"A=B", nullptr});
-  eth.Run([&]() { fexecve(printenv_fd, eth.GetArgs(), eth.GetEnv()); }, 0, "A=B\n");
+
+  std::string expected_output("A=B\n");
+  append_llvm_cov_env_var(expected_output);
+
+  eth.Run([&]() { fexecve(printenv_fd, eth.GetArgs(), eth.GetEnv()); }, 0, expected_output.c_str());
   close(printenv_fd);
 }