Merge changes Ia7200bf0,I86999bb7

* changes:
  versioner: fix leak.
  versioner: add symlink for dependencies.
diff --git a/libc/Android.bp b/libc/Android.bp
index e8175f4..b2ebe09 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1,6 +1,7 @@
 // Define the common source files for all the libc instances
 // =========================================================
 libc_common_src_files = [
+    "async_safe/async_safe_log.cpp",
     "bionic/ether_aton.c",
     "bionic/ether_ntoa.c",
     "bionic/fts.c",
@@ -58,7 +59,10 @@
     asflags: libc_common_flags,
     conlyflags: ["-std=gnu99"],
     cppflags: [],
-    include_dirs: ["external/jemalloc/include"],
+    include_dirs: [
+        "bionic/libc/async_safe/include",
+        "external/jemalloc/include",
+    ],
 
     stl: "none",
     system_shared_libs: [],
@@ -1346,7 +1350,6 @@
         "bionic/__libc_current_sigrtmax.cpp",
         "bionic/__libc_current_sigrtmin.cpp",
         "bionic/libc_init_common.cpp",
-        "bionic/libc_logging.cpp",
         "bionic/libgen.cpp",
         "bionic/link.cpp",
         "bionic/locale.cpp",
@@ -1705,7 +1708,7 @@
             "bionic/libc_init_static.cpp",
         ],
         cflags: ["-DLIBC_STATIC"],
-        whole_static_libs: ["libc_init_static", "libjemalloc"],
+        whole_static_libs: ["libc_init_static"],
     },
     shared: {
         srcs: [
@@ -1717,7 +1720,6 @@
             "bionic/NetdClient.cpp",
             "arch-common/bionic/crtend_so.S",
         ],
-        whole_static_libs: ["libjemalloc"],
     },
 
     required: ["tzdata"],
@@ -1740,7 +1742,7 @@
     // you wanted!
 
     shared_libs: ["libdl"],
-    whole_static_libs: ["libc_common"],
+    whole_static_libs: ["libc_common", "libjemalloc"],
 
     nocrt: true,
 
@@ -1793,19 +1795,6 @@
 }
 
 // ========================================================
-// libc_logging.a
-// ========================================================
-cc_library_static {
-    defaults: ["libc_defaults"],
-
-    srcs: [
-        "bionic/libc_logging.cpp",
-    ],
-
-    name: "libc_logging",
-}
-
-// ========================================================
 // libstdc++.so + libstdc++.a
 // ========================================================
 cc_library {
@@ -1818,9 +1807,7 @@
     ],
     name: "libstdc++",
     system_shared_libs: ["libc"],
-    shared: {
-        static_libs: ["libc_logging"],
-    },
+		static_libs: ["libasync_safe"],
 
     //TODO (dimitry): This is to work around b/24465209. Remove after root cause is fixed
     arch: {
@@ -2076,7 +2063,7 @@
 }
 
 ndk_headers {
-    name: "libc_android",
+    name: "libc_kernel_android_uapi_linux",
     from: "kernel/android/uapi/linux",
     to: "linux",
     srcs: ["kernel/android/uapi/linux/**/*.h"],
@@ -2084,6 +2071,14 @@
 }
 
 ndk_headers {
+    name: "libc_kernel_android_scsi",
+    from: "kernel/android/scsi",
+    to: "scsi",
+    srcs: ["kernel/android/scsi/**/*.h"],
+    license: "NOTICE",
+}
+
+ndk_headers {
     name: "libc_asm_arm",
     from: "kernel/uapi/asm-arm",
     to: "arm-linux-androideabi",
diff --git a/libc/arch-arm/bionic/atexit_legacy.c b/libc/arch-arm/bionic/atexit_legacy.c
index c0d704d..7254017 100644
--- a/libc/arch-arm/bionic/atexit_legacy.c
+++ b/libc/arch-arm/bionic/atexit_legacy.c
@@ -29,7 +29,7 @@
 #include <sys/types.h>
 #include <stdio.h>
 
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
 
 /*
  * This source file should only be included by libc.so, its purpose is
@@ -53,7 +53,7 @@
      */
     static char const warning[] = "WARNING: generic atexit() called from legacy shared library\n";
 
-    __libc_format_log(ANDROID_LOG_WARN, "libc", warning);
+    async_safe_format_log(ANDROID_LOG_WARN, "libc", warning);
     fprintf(stderr, warning);
 
     return (__cxa_atexit((void (*)(void *))func, NULL, NULL));
diff --git a/libc/arch-mips/bionic/cacheflush.cpp b/libc/arch-mips/bionic/cacheflush.cpp
index 98c0bd4..380ad90 100644
--- a/libc/arch-mips/bionic/cacheflush.cpp
+++ b/libc/arch-mips/bionic/cacheflush.cpp
@@ -29,7 +29,7 @@
 #include <unistd.h>
 #include <sys/cachectl.h>
 
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
 
 // Linux historically defines a cacheflush(3) routine for MIPS
 // with this signature:
@@ -50,7 +50,8 @@
     // It looks like this is really a MIPS-style cacheflush call.
     static bool warned = false;
     if (!warned) {
-      __libc_format_log(ANDROID_LOG_WARN, "libc", "cacheflush called with (start,len) instead of (start,end)");
+      async_safe_format_log(ANDROID_LOG_WARN, "libc",
+                            "cacheflush called with (start,len) instead of (start,end)");
       warned = true;
     }
     end += start;
diff --git a/libc/async_safe/Android.bp b/libc/async_safe/Android.bp
new file mode 100644
index 0000000..9e36d97
--- /dev/null
+++ b/libc/async_safe/Android.bp
@@ -0,0 +1,15 @@
+// ========================================================
+// libasync_safe.a
+// ========================================================
+cc_library_static {
+    defaults: ["libc_defaults"],
+    srcs: [
+        "async_safe_log.cpp",
+    ],
+
+    name: "libasync_safe",
+
+    include_dirs: ["bionic/libc"],
+
+    export_include_dirs: ["include"],
+}
diff --git a/libc/async_safe/async_safe_log.cpp b/libc/async_safe/async_safe_log.cpp
new file mode 100644
index 0000000..372f385
--- /dev/null
+++ b/libc/async_safe/async_safe_log.cpp
@@ -0,0 +1,576 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <android/set_abort_message.h>
+#include <async_safe/log.h>
+
+#include "private/CachedProperty.h"
+#include "private/ScopedPthreadMutexLocker.h"
+
+// Must be kept in sync with frameworks/base/core/java/android/util/EventLog.java.
+enum AndroidEventLogType {
+  EVENT_TYPE_INT = 0,
+  EVENT_TYPE_LONG = 1,
+  EVENT_TYPE_STRING = 2,
+  EVENT_TYPE_LIST = 3,
+  EVENT_TYPE_FLOAT = 4,
+};
+
+struct BufferOutputStream {
+ public:
+  BufferOutputStream(char* buffer, size_t size) : total(0) {
+    buffer_ = buffer;
+    end_ = buffer + size - 1;
+    pos_ = buffer_;
+    pos_[0] = '\0';
+  }
+
+  ~BufferOutputStream() {}
+
+  void Send(const char* data, int len) {
+    if (len < 0) {
+      len = strlen(data);
+    }
+
+    total += len;
+
+    while (len > 0) {
+      int avail = end_ - pos_;
+      if (avail == 0) {
+        return;
+      }
+      if (avail > len) {
+        avail = len;
+      }
+      memcpy(pos_, data, avail);
+      pos_ += avail;
+      pos_[0] = '\0';
+      len -= avail;
+    }
+  }
+
+  size_t total;
+
+ private:
+  char* buffer_;
+  char* pos_;
+  char* end_;
+};
+
+struct FdOutputStream {
+ public:
+  explicit FdOutputStream(int fd) : total(0), fd_(fd) {}
+
+  void Send(const char* data, int len) {
+    if (len < 0) {
+      len = strlen(data);
+    }
+
+    total += len;
+
+    while (len > 0) {
+      int rc = TEMP_FAILURE_RETRY(write(fd_, data, len));
+      if (rc == -1) {
+        return;
+      }
+      data += rc;
+      len -= rc;
+    }
+  }
+
+  size_t total;
+
+ private:
+  int fd_;
+};
+
+/*** formatted output implementation
+ ***/
+
+/* Parse a decimal string from 'format + *ppos',
+ * return the value, and writes the new position past
+ * the decimal string in '*ppos' on exit.
+ *
+ * NOTE: Does *not* handle a sign prefix.
+ */
+static unsigned parse_decimal(const char* format, int* ppos) {
+  const char* p = format + *ppos;
+  unsigned result = 0;
+
+  for (;;) {
+    int ch = *p;
+    unsigned d = static_cast<unsigned>(ch - '0');
+
+    if (d >= 10U) {
+      break;
+    }
+
+    result = result * 10 + d;
+    p++;
+  }
+  *ppos = p - format;
+  return result;
+}
+
+// Writes number 'value' in base 'base' into buffer 'buf' of size 'buf_size' bytes.
+// Assumes that buf_size > 0.
+static void format_unsigned(char* buf, size_t buf_size, uint64_t value, int base, bool caps) {
+  char* p = buf;
+  char* end = buf + buf_size - 1;
+
+  // Generate digit string in reverse order.
+  while (value) {
+    unsigned d = value % base;
+    value /= base;
+    if (p != end) {
+      char ch;
+      if (d < 10) {
+        ch = '0' + d;
+      } else {
+        ch = (caps ? 'A' : 'a') + (d - 10);
+      }
+      *p++ = ch;
+    }
+  }
+
+  // Special case for 0.
+  if (p == buf) {
+    if (p != end) {
+      *p++ = '0';
+    }
+  }
+  *p = '\0';
+
+  // Reverse digit string in-place.
+  size_t length = p - buf;
+  for (size_t i = 0, j = length - 1; i < j; ++i, --j) {
+    char ch = buf[i];
+    buf[i] = buf[j];
+    buf[j] = ch;
+  }
+}
+
+static void format_integer(char* buf, size_t buf_size, uint64_t value, char conversion) {
+  // Decode the conversion specifier.
+  int is_signed = (conversion == 'd' || conversion == 'i' || conversion == 'o');
+  int base = 10;
+  if (conversion == 'x' || conversion == 'X') {
+    base = 16;
+  } else if (conversion == 'o') {
+    base = 8;
+  }
+  bool caps = (conversion == 'X');
+
+  if (is_signed && static_cast<int64_t>(value) < 0) {
+    buf[0] = '-';
+    buf += 1;
+    buf_size -= 1;
+    value = static_cast<uint64_t>(-static_cast<int64_t>(value));
+  }
+  format_unsigned(buf, buf_size, value, base, caps);
+}
+
+template <typename Out>
+static void SendRepeat(Out& o, char ch, int count) {
+  char pad[8];
+  memset(pad, ch, sizeof(pad));
+
+  const int pad_size = static_cast<int>(sizeof(pad));
+  while (count > 0) {
+    int avail = count;
+    if (avail > pad_size) {
+      avail = pad_size;
+    }
+    o.Send(pad, avail);
+    count -= avail;
+  }
+}
+
+/* Perform formatted output to an output target 'o' */
+template <typename Out>
+static void out_vformat(Out& o, const char* format, va_list args) {
+  int nn = 0;
+
+  for (;;) {
+    int mm;
+    int padZero = 0;
+    int padLeft = 0;
+    char sign = '\0';
+    int width = -1;
+    int prec = -1;
+    size_t bytelen = sizeof(int);
+    int slen;
+    char buffer[32]; /* temporary buffer used to format numbers */
+
+    char c;
+
+    /* first, find all characters that are not 0 or '%' */
+    /* then send them to the output directly */
+    mm = nn;
+    do {
+      c = format[mm];
+      if (c == '\0' || c == '%') break;
+      mm++;
+    } while (1);
+
+    if (mm > nn) {
+      o.Send(format + nn, mm - nn);
+      nn = mm;
+    }
+
+    /* is this it ? then exit */
+    if (c == '\0') break;
+
+    /* nope, we are at a '%' modifier */
+    nn++;  // skip it
+
+    /* parse flags */
+    for (;;) {
+      c = format[nn++];
+      if (c == '\0') { /* single trailing '%' ? */
+        c = '%';
+        o.Send(&c, 1);
+        return;
+      } else if (c == '0') {
+        padZero = 1;
+        continue;
+      } else if (c == '-') {
+        padLeft = 1;
+        continue;
+      } else if (c == ' ' || c == '+') {
+        sign = c;
+        continue;
+      }
+      break;
+    }
+
+    /* parse field width */
+    if ((c >= '0' && c <= '9')) {
+      nn--;
+      width = static_cast<int>(parse_decimal(format, &nn));
+      c = format[nn++];
+    }
+
+    /* parse precision */
+    if (c == '.') {
+      prec = static_cast<int>(parse_decimal(format, &nn));
+      c = format[nn++];
+    }
+
+    /* length modifier */
+    switch (c) {
+      case 'h':
+        bytelen = sizeof(short);
+        if (format[nn] == 'h') {
+          bytelen = sizeof(char);
+          nn += 1;
+        }
+        c = format[nn++];
+        break;
+      case 'l':
+        bytelen = sizeof(long);
+        if (format[nn] == 'l') {
+          bytelen = sizeof(long long);
+          nn += 1;
+        }
+        c = format[nn++];
+        break;
+      case 'z':
+        bytelen = sizeof(size_t);
+        c = format[nn++];
+        break;
+      case 't':
+        bytelen = sizeof(ptrdiff_t);
+        c = format[nn++];
+        break;
+      default:;
+    }
+
+    /* conversion specifier */
+    const char* str = buffer;
+    if (c == 's') {
+      /* string */
+      str = va_arg(args, const char*);
+      if (str == NULL) {
+        str = "(null)";
+      }
+    } else if (c == 'c') {
+      /* character */
+      /* NOTE: char is promoted to int when passed through the stack */
+      buffer[0] = static_cast<char>(va_arg(args, int));
+      buffer[1] = '\0';
+    } else if (c == 'p') {
+      uint64_t value = reinterpret_cast<uintptr_t>(va_arg(args, void*));
+      buffer[0] = '0';
+      buffer[1] = 'x';
+      format_integer(buffer + 2, sizeof(buffer) - 2, value, 'x');
+    } else if (c == 'd' || c == 'i' || c == 'o' || c == 'u' || c == 'x' || c == 'X') {
+      /* integers - first read value from stack */
+      uint64_t value;
+      int is_signed = (c == 'd' || c == 'i' || c == 'o');
+
+      /* NOTE: int8_t and int16_t are promoted to int when passed
+       *       through the stack
+       */
+      switch (bytelen) {
+        case 1:
+          value = static_cast<uint8_t>(va_arg(args, int));
+          break;
+        case 2:
+          value = static_cast<uint16_t>(va_arg(args, int));
+          break;
+        case 4:
+          value = va_arg(args, uint32_t);
+          break;
+        case 8:
+          value = va_arg(args, uint64_t);
+          break;
+        default:
+          return; /* should not happen */
+      }
+
+      /* sign extension, if needed */
+      if (is_signed) {
+        int shift = 64 - 8 * bytelen;
+        value = static_cast<uint64_t>((static_cast<int64_t>(value << shift)) >> shift);
+      }
+
+      /* format the number properly into our buffer */
+      format_integer(buffer, sizeof(buffer), value, c);
+    } else if (c == '%') {
+      buffer[0] = '%';
+      buffer[1] = '\0';
+    } else {
+      __assert(__FILE__, __LINE__, "conversion specifier unsupported");
+    }
+
+    /* if we are here, 'str' points to the content that must be
+     * outputted. handle padding and alignment now */
+
+    slen = strlen(str);
+
+    if (sign != '\0' || prec != -1) {
+      __assert(__FILE__, __LINE__, "sign/precision unsupported");
+    }
+
+    if (slen < width && !padLeft) {
+      char padChar = padZero ? '0' : ' ';
+      SendRepeat(o, padChar, width - slen);
+    }
+
+    o.Send(str, slen);
+
+    if (slen < width && padLeft) {
+      char padChar = padZero ? '0' : ' ';
+      SendRepeat(o, padChar, width - slen);
+    }
+  }
+}
+
+int async_safe_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) {
+  BufferOutputStream os(buffer, buffer_size);
+  va_list args;
+  va_start(args, format);
+  out_vformat(os, format, args);
+  va_end(args);
+  return os.total;
+}
+
+int async_safe_format_buffer_va_list(char* buffer, size_t buffer_size, const char* format,
+                                     va_list args) {
+  BufferOutputStream os(buffer, buffer_size);
+  out_vformat(os, format, args);
+  return os.total;
+}
+
+int async_safe_format_fd(int fd, const char* format, ...) {
+  FdOutputStream os(fd);
+  va_list args;
+  va_start(args, format);
+  out_vformat(os, format, args);
+  va_end(args);
+  return os.total;
+}
+
+static int write_stderr(const char* tag, const char* msg) {
+  iovec vec[4];
+  vec[0].iov_base = const_cast<char*>(tag);
+  vec[0].iov_len = strlen(tag);
+  vec[1].iov_base = const_cast<char*>(": ");
+  vec[1].iov_len = 2;
+  vec[2].iov_base = const_cast<char*>(msg);
+  vec[2].iov_len = strlen(msg);
+  vec[3].iov_base = const_cast<char*>("\n");
+  vec[3].iov_len = 1;
+
+  int result = TEMP_FAILURE_RETRY(writev(STDERR_FILENO, vec, 4));
+  return result;
+}
+
+static int open_log_socket() {
+  // ToDo: Ideally we want this to fail if the gid of the current
+  // process is AID_LOGD, but will have to wait until we have
+  // registered this in private/android_filesystem_config.h. We have
+  // found that all logd crashes thus far have had no problem stuffing
+  // the UNIX domain socket and moving on so not critical *today*.
+
+  int log_fd = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
+  if (log_fd == -1) {
+    return -1;
+  }
+
+  union {
+    struct sockaddr addr;
+    struct sockaddr_un addrUn;
+  } u;
+  memset(&u, 0, sizeof(u));
+  u.addrUn.sun_family = AF_UNIX;
+  strlcpy(u.addrUn.sun_path, "/dev/socket/logdw", sizeof(u.addrUn.sun_path));
+
+  if (TEMP_FAILURE_RETRY(connect(log_fd, &u.addr, sizeof(u.addrUn))) != 0) {
+    close(log_fd);
+    return -1;
+  }
+
+  return log_fd;
+}
+
+static clockid_t log_clockid() {
+  static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+  ScopedPthreadMutexLocker locker(&mutex);
+
+  static CachedProperty ro_logd_timestamp("ro.logd.timestamp");
+  static CachedProperty persist_logd_timestamp("persist.logd.timestamp");
+
+  char ch = persist_logd_timestamp.Get()[0];
+  if (ch == '\0') ch = ro_logd_timestamp.Get()[0];
+
+  return (tolower(ch) == 'm') ? CLOCK_MONOTONIC : CLOCK_REALTIME;
+}
+
+struct log_time {  // Wire format
+  uint32_t tv_sec;
+  uint32_t tv_nsec;
+};
+
+int async_safe_write_log(int priority, const char* tag, const char* msg) {
+  int main_log_fd = open_log_socket();
+  if (main_log_fd == -1) {
+    // Try stderr instead.
+    return write_stderr(tag, msg);
+  }
+
+  iovec vec[6];
+  char log_id = (priority == ANDROID_LOG_FATAL) ? LOG_ID_CRASH : LOG_ID_MAIN;
+  vec[0].iov_base = &log_id;
+  vec[0].iov_len = sizeof(log_id);
+  uint16_t tid = gettid();
+  vec[1].iov_base = &tid;
+  vec[1].iov_len = sizeof(tid);
+  timespec ts;
+  clock_gettime(log_clockid(), &ts);
+  log_time realtime_ts;
+  realtime_ts.tv_sec = ts.tv_sec;
+  realtime_ts.tv_nsec = ts.tv_nsec;
+  vec[2].iov_base = &realtime_ts;
+  vec[2].iov_len = sizeof(realtime_ts);
+
+  vec[3].iov_base = &priority;
+  vec[3].iov_len = 1;
+  vec[4].iov_base = const_cast<char*>(tag);
+  vec[4].iov_len = strlen(tag) + 1;
+  vec[5].iov_base = const_cast<char*>(msg);
+  vec[5].iov_len = strlen(msg) + 1;
+
+  int result = TEMP_FAILURE_RETRY(writev(main_log_fd, vec, sizeof(vec) / sizeof(vec[0])));
+  close(main_log_fd);
+  return result;
+}
+
+int async_safe_format_log_va_list(int priority, const char* tag, const char* format, va_list args) {
+  char buffer[1024];
+  BufferOutputStream os(buffer, sizeof(buffer));
+  out_vformat(os, format, args);
+  return async_safe_write_log(priority, tag, buffer);
+}
+
+int async_safe_format_log(int priority, const char* tag, const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  int result = async_safe_format_log_va_list(priority, tag, format, args);
+  va_end(args);
+  return result;
+}
+
+void async_safe_fatal_va_list(const char* prefix, const char* format, va_list args) {
+  char msg[1024];
+  BufferOutputStream os(msg, sizeof(msg));
+
+  if (prefix) {
+    os.Send(prefix, strlen(prefix));
+    os.Send(": ", 2);
+  }
+
+  out_vformat(os, format, args);
+
+  // Log to stderr for the benefit of "adb shell" users and gtests.
+  struct iovec iov[2] = {
+      {msg, os.total}, {const_cast<char*>("\n"), 1},
+  };
+  TEMP_FAILURE_RETRY(writev(2, iov, 2));
+
+  // Log to the log for the benefit of regular app developers (whose stdout and stderr are closed).
+  async_safe_write_log(ANDROID_LOG_FATAL, "libc", msg);
+
+  android_set_abort_message(msg);
+}
+
+void async_safe_fatal(const char* fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+  async_safe_fatal_va_list(nullptr, fmt, args);
+  va_end(args);
+  abort();
+}
diff --git a/libc/private/libc_logging.h b/libc/async_safe/include/async_safe/log.h
similarity index 61%
rename from libc/private/libc_logging.h
rename to libc/async_safe/include/async_safe/log.h
index 73bc9a5..f93f672 100644
--- a/libc/private/libc_logging.h
+++ b/libc/async_safe/include/async_safe/log.h
@@ -26,14 +26,16 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _LIBC_LOGGING_H
-#define _LIBC_LOGGING_H
+#ifndef _ASYNC_SAFE_LOG_LOG_H
+#define _ASYNC_SAFE_LOG_LOG_H
 
 #include <sys/cdefs.h>
 #include <stdarg.h>
 #include <stddef.h>
 #include <stdint.h>
 
+// These functions do not allocate memory to send data to the log.
+
 __BEGIN_DECLS
 
 enum {
@@ -63,10 +65,16 @@
 };
 
 // Formats a message to the log (priority 'fatal'), then aborts.
-__noreturn void __libc_fatal(const char* _Nonnull, ...) __printflike(1, 2);
+__noreturn void async_safe_fatal(const char* _Nonnull fmt, ...) __printflike(1, 2);
 
-// Formats a message to the log (priority 'fatal'), prefixed by "FORTIFY: ", then aborts.
-__noreturn void __fortify_fatal(const char* _Nonnull, ...) __printflike(1, 2);
+// This function does return, so callers that want to abort, must do so themselves.
+#if defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+void async_safe_fatal_va_list(
+    const char* _Nullable prefix, const char* _Nonnull fmt, va_list);
+#else // defined(__mips__) || defined(__i386__)
+void async_safe_fatal_va_list(
+    const char* _Nullable prefix, const char* _Nonnull fmt, va_list _Nonnull);
+#endif
 
 //
 // Formatting routines for the C library's internal debugging.
@@ -74,29 +82,31 @@
 // These are async signal safe, so they can be called from signal handlers.
 //
 
-int __libc_format_buffer(char* _Nonnull buf, size_t size, const char* _Nonnull fmt, ...) __printflike(3, 4);
+int async_safe_format_buffer(char* _Nonnull buf, size_t size, const char* _Nonnull fmt, ...) __printflike(3, 4);
 
 #if defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
-int __libc_format_buffer_va_list(char* _Nonnull buffer, size_t buffer_size,
-                                 const char* _Nonnull format, va_list args);
+int async_safe_format_buffer_va_list(
+    char* _Nonnull buffer, size_t buffer_size, const char* _Nonnull format, va_list args);
 #else // defined(__mips__) || defined(__i386__)
-int __libc_format_buffer_va_list(char* _Nonnull buffer, size_t buffer_size,
-                                 const char* _Nonnull format, va_list _Nonnull args);
+int async_safe_format_buffer_va_list(
+    char* _Nonnull buffer, size_t buffer_size, const char* _Nonnull format, va_list _Nonnull args);
 #endif
 
-int __libc_format_fd(int fd, const char* _Nonnull format , ...) __printflike(2, 3);
-int __libc_format_log(int pri, const char* _Nonnull tag, const char* _Nonnull fmt, ...) __printflike(3, 4);
+int async_safe_format_fd(int fd, const char* _Nonnull format , ...) __printflike(2, 3);
+int async_safe_format_log(int pri, const char* _Nonnull tag, const char* _Nonnull fmt, ...) __printflike(3, 4);
 #if defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
-int __libc_format_log_va_list(int pri, const char* _Nonnull tag, const char* _Nonnull fmt, va_list ap);
+int async_safe_format_log_va_list(
+    int pri, const char* _Nonnull tag, const char* _Nonnull fmt, va_list ap);
 #else // defined(__mips__) || defined(__i386__)
-int __libc_format_log_va_list(int pri, const char* _Nonnull tag, const char* _Nonnull fmt, va_list _Nonnull ap);
+int async_safe_format_log_va_list(
+    int pri, const char* _Nonnull tag, const char* _Nonnull fmt, va_list _Nonnull ap);
 #endif
-int __libc_write_log(int pri, const char* _Nonnull tag, const char* _Nonnull msg);
+int async_safe_write_log(int pri, const char* _Nonnull tag, const char* _Nonnull msg);
 
 #define CHECK(predicate) \
   do { \
     if (!(predicate)) { \
-      __libc_fatal("%s:%d: %s CHECK '" #predicate "' failed", \
+      async_safe_fatal("%s:%d: %s CHECK '" #predicate "' failed", \
           __FILE__, __LINE__, __FUNCTION__); \
     } \
   } while(0)
diff --git a/libc/bionic/NetdClient.cpp b/libc/bionic/NetdClient.cpp
index b117d72..a1071d2 100644
--- a/libc/bionic/NetdClient.cpp
+++ b/libc/bionic/NetdClient.cpp
@@ -18,7 +18,8 @@
 #error NetdClient.cpp should NOT be included in static libc builds.
 #endif
 
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
+
 #include "private/NetdClientDispatch.h"
 
 #include <dlfcn.h>
@@ -53,6 +54,6 @@
 
 extern "C" __LIBC_HIDDEN__ void netdClientInit() {
     if (pthread_once(&netdClientInitOnce, netdClientInitImpl)) {
-        __libc_format_log(ANDROID_LOG_ERROR, "netdClient", "Failed to initialize netd_client");
+        async_safe_format_log(ANDROID_LOG_ERROR, "netdClient", "Failed to initialize netd_client");
     }
 }
diff --git a/libc/bionic/__cxa_pure_virtual.cpp b/libc/bionic/__cxa_pure_virtual.cpp
index 30b581f..00a4d90 100644
--- a/libc/bionic/__cxa_pure_virtual.cpp
+++ b/libc/bionic/__cxa_pure_virtual.cpp
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#include <private/libc_logging.h>
+#include <async_safe/log.h>
 
 extern "C" void __cxa_pure_virtual() {
-  __libc_fatal("Pure virtual function called. Are you calling virtual methods from a destructor?");
+  async_safe_fatal("Pure virtual function called. Are you calling virtual methods from a destructor?");
 }
diff --git a/libc/bionic/__libc_current_sigrtmax.cpp b/libc/bionic/__libc_current_sigrtmax.cpp
index 27fcb35..32179bb 100644
--- a/libc/bionic/__libc_current_sigrtmax.cpp
+++ b/libc/bionic/__libc_current_sigrtmax.cpp
@@ -29,5 +29,7 @@
 #include <signal.h>
 
 int __libc_current_sigrtmax(void) {
+  // If you change this, also change __ndk_legacy___libc_current_sigrtmax
+  // in <android/legacy_signal_inlines.h> to match.
   return __SIGRTMAX;
 }
diff --git a/libc/bionic/__libc_current_sigrtmin.cpp b/libc/bionic/__libc_current_sigrtmin.cpp
index 7c93267..f3b2bf6 100644
--- a/libc/bionic/__libc_current_sigrtmin.cpp
+++ b/libc/bionic/__libc_current_sigrtmin.cpp
@@ -34,5 +34,7 @@
 // __SIGRTMIN + 3 is reserved for triggering native stack dumps.
 
 int __libc_current_sigrtmin(void) {
+  // If you change this, also change __ndk_legacy___libc_current_sigrtmin
+  // in <android/legacy_signal_inlines.h> to match.
   return __SIGRTMIN + 4;
 }
diff --git a/libc/bionic/__stack_chk_fail.cpp b/libc/bionic/__stack_chk_fail.cpp
index cb039cf..5f5a5f6 100644
--- a/libc/bionic/__stack_chk_fail.cpp
+++ b/libc/bionic/__stack_chk_fail.cpp
@@ -28,9 +28,10 @@
 
 #include <stdlib.h>
 
+#include <async_safe/log.h>
+
 #include "private/bionic_ssp.h"
-#include "private/libc_logging.h"
 
 void __stack_chk_fail() {
-  __libc_fatal("stack corruption detected (-fstack-protector)");
+  async_safe_fatal("stack corruption detected (-fstack-protector)");
 }
diff --git a/libc/bionic/assert.cpp b/libc/bionic/assert.cpp
index 985fc38..41831cb 100644
--- a/libc/bionic/assert.cpp
+++ b/libc/bionic/assert.cpp
@@ -30,16 +30,16 @@
 
 #include <assert.h>
 
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
 
 void __assert(const char* file, int line, const char* failed_expression) {
-  __libc_fatal("%s:%d: assertion \"%s\" failed", file, line, failed_expression);
+  async_safe_fatal("%s:%d: assertion \"%s\" failed", file, line, failed_expression);
 }
 
 void __assert2(const char* file, int line, const char* function, const char* failed_expression) {
-  __libc_fatal("%s:%d: %s: assertion \"%s\" failed", file, line, function, failed_expression);
+  async_safe_fatal("%s:%d: %s: assertion \"%s\" failed", file, line, function, failed_expression);
 }
 
 extern "C" __LIBC_HIDDEN__ void longjmperror() {
-  __libc_fatal("longjmp botch");
+  async_safe_fatal("longjmp botch");
 }
diff --git a/libc/bionic/bionic_arc4random.cpp b/libc/bionic/bionic_arc4random.cpp
index ba3b4e1..a4842f6 100644
--- a/libc/bionic/bionic_arc4random.cpp
+++ b/libc/bionic/bionic_arc4random.cpp
@@ -35,8 +35,9 @@
 #include <syscall.h>
 #include <unistd.h>
 
+#include <async_safe/log.h>
+
 #include "private/KernelArgumentBlock.h"
-#include "private/libc_logging.h"
 
 bool __libc_arc4random_has_unlimited_entropy() {
   static bool have_urandom = access("/dev/urandom", R_OK) == 0;
@@ -53,8 +54,8 @@
 
   static size_t at_random_bytes_consumed = 0;
   if (at_random_bytes_consumed + n > 16) {
-    __libc_fatal("ran out of AT_RANDOM bytes, have %zu, requested %zu",
-                 16 - at_random_bytes_consumed, n);
+    async_safe_fatal("ran out of AT_RANDOM bytes, have %zu, requested %zu",
+                     16 - at_random_bytes_consumed, n);
   }
 
   memcpy(buf, reinterpret_cast<char*>(args.getauxval(AT_RANDOM)) + at_random_bytes_consumed, n);
diff --git a/libc/bionic/bionic_systrace.cpp b/libc/bionic/bionic_systrace.cpp
index 5699f6e..970a92b 100644
--- a/libc/bionic/bionic_systrace.cpp
+++ b/libc/bionic/bionic_systrace.cpp
@@ -23,7 +23,6 @@
 #include "private/bionic_lock.h"
 #include "private/bionic_systrace.h"
 #include "private/CachedProperty.h"
-#include "private/libc_logging.h"
 
 #include <cutils/trace.h> // For ATRACE_TAG_BIONIC.
 
diff --git a/libc/bionic/grp_pwd.cpp b/libc/bionic/grp_pwd.cpp
index 5d565c4..078a0b3 100644
--- a/libc/bionic/grp_pwd.cpp
+++ b/libc/bionic/grp_pwd.cpp
@@ -41,7 +41,6 @@
 #include "private/bionic_macros.h"
 #include "private/grp_pwd.h"
 #include "private/ErrnoRestorer.h"
-#include "private/libc_logging.h"
 
 // Generated android_ids array
 #include "generated_android_ids.h"
diff --git a/libc/bionic/icu.cpp b/libc/bionic/icu.cpp
index abc0eec..944a3f8 100644
--- a/libc/bionic/icu.cpp
+++ b/libc/bionic/icu.cpp
@@ -33,7 +33,7 @@
 #include <pthread.h>
 #include <stdlib.h>
 
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
 
 // Allowed icu4c version numbers are in the range [44, 999].
 // Gingerbread's icu4c 4.4 is the minimum supported ICU version.
@@ -68,7 +68,7 @@
   free(namelist);
 
   if (max_version == -1 || max_version < ICUDATA_VERSION_MIN) {
-    __libc_write_log(ANDROID_LOG_ERROR, "bionic-icu", "couldn't find an ICU .dat file");
+    async_safe_write_log(ANDROID_LOG_ERROR, "bionic-icu", "couldn't find an ICU .dat file");
     return false;
   }
 
@@ -76,7 +76,8 @@
 
   g_libicuuc_handle = dlopen("libicuuc.so", RTLD_LOCAL);
   if (g_libicuuc_handle == nullptr) {
-    __libc_format_log(ANDROID_LOG_ERROR, "bionic-icu", "couldn't open libicuuc.so: %s", dlerror());
+    async_safe_format_log(ANDROID_LOG_ERROR, "bionic-icu", "couldn't open libicuuc.so: %s",
+                          dlerror());
     return false;
   }
 
@@ -93,7 +94,8 @@
 
   void* symbol = dlsym(g_libicuuc_handle, versioned_symbol_name);
   if (symbol == nullptr) {
-    __libc_format_log(ANDROID_LOG_ERROR, "bionic-icu", "couldn't find %s", versioned_symbol_name);
+    async_safe_format_log(ANDROID_LOG_ERROR, "bionic-icu", "couldn't find %s",
+                          versioned_symbol_name);
   }
   return symbol;
 }
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index 970a49c..d267b68 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -41,12 +41,13 @@
 #include <sys/time.h>
 #include <unistd.h>
 
+#include <async_safe/log.h>
+
 #include "private/KernelArgumentBlock.h"
 #include "private/WriteProtected.h"
 #include "private/bionic_auxv.h"
 #include "private/bionic_globals.h"
 #include "private/bionic_tls.h"
-#include "private/libc_logging.h"
 #include "private/thread_private.h"
 #include "pthread_internal.h"
 
@@ -96,8 +97,8 @@
 #if !defined(__LP64__)
 static void __check_max_thread_id() {
   if (gettid() > 65535) {
-    __libc_fatal("Limited by the size of pthread_mutex_t, 32 bit bionic libc only accepts "
-                 "pid <= 65535, but current pid is %d", gettid());
+    async_safe_fatal("Limited by the size of pthread_mutex_t, 32 bit bionic libc only accepts "
+                     "pid <= 65535, but current pid is %d", gettid());
   }
 }
 #endif
@@ -303,11 +304,11 @@
 #if !defined(__LP64__)
   int old_value = personality(0xffffffff);
   if (old_value == -1) {
-    __libc_fatal("error getting old personality value: %s", strerror(errno));
+    async_safe_fatal("error getting old personality value: %s", strerror(errno));
   }
 
   if (personality((static_cast<unsigned int>(old_value) & ~PER_MASK) | PER_LINUX32) == -1) {
-    __libc_fatal("error setting PER_LINUX32 personality: %s", strerror(errno));
+    async_safe_fatal("error setting PER_LINUX32 personality: %s", strerror(errno));
   }
 #endif
 }
diff --git a/libc/bionic/libc_logging.cpp b/libc/bionic/libc_logging.cpp
deleted file mode 100644
index 54664d9..0000000
--- a/libc/bionic/libc_logging.cpp
+++ /dev/null
@@ -1,584 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-// Relative paths so we can #include this .cpp file for testing.
-#include "../private/CachedProperty.h"
-#include "../private/libc_logging.h"
-#include "../private/ScopedPthreadMutexLocker.h"
-
-#include <android/set_abort_message.h>
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <sys/un.h>
-#include <time.h>
-#include <unistd.h>
-
-// Must be kept in sync with frameworks/base/core/java/android/util/EventLog.java.
-enum AndroidEventLogType {
-  EVENT_TYPE_INT      = 0,
-  EVENT_TYPE_LONG     = 1,
-  EVENT_TYPE_STRING   = 2,
-  EVENT_TYPE_LIST     = 3,
-  EVENT_TYPE_FLOAT    = 4,
-};
-
-struct BufferOutputStream {
- public:
-  BufferOutputStream(char* buffer, size_t size) : total(0) {
-    buffer_ = buffer;
-    end_ = buffer + size - 1;
-    pos_ = buffer_;
-    pos_[0] = '\0';
-  }
-
-  ~BufferOutputStream() {
-  }
-
-  void Send(const char* data, int len) {
-    if (len < 0) {
-      len = strlen(data);
-    }
-
-    total += len;
-
-    while (len > 0) {
-      int avail = end_ - pos_;
-      if (avail == 0) {
-        return;
-      }
-      if (avail > len) {
-        avail = len;
-      }
-      memcpy(pos_, data, avail);
-      pos_ += avail;
-      pos_[0] = '\0';
-      len -= avail;
-    }
-  }
-
-  size_t total;
-
- private:
-  char* buffer_;
-  char* pos_;
-  char* end_;
-};
-
-struct FdOutputStream {
- public:
-  explicit FdOutputStream(int fd) : total(0), fd_(fd) {
-  }
-
-  void Send(const char* data, int len) {
-    if (len < 0) {
-      len = strlen(data);
-    }
-
-    total += len;
-
-    while (len > 0) {
-      int rc = TEMP_FAILURE_RETRY(write(fd_, data, len));
-      if (rc == -1) {
-        return;
-      }
-      data += rc;
-      len -= rc;
-    }
-  }
-
-  size_t total;
-
- private:
-  int fd_;
-};
-
-/*** formatted output implementation
- ***/
-
-/* Parse a decimal string from 'format + *ppos',
- * return the value, and writes the new position past
- * the decimal string in '*ppos' on exit.
- *
- * NOTE: Does *not* handle a sign prefix.
- */
-static unsigned parse_decimal(const char *format, int *ppos) {
-    const char* p = format + *ppos;
-    unsigned result = 0;
-
-    for (;;) {
-        int ch = *p;
-        unsigned d = static_cast<unsigned>(ch - '0');
-
-        if (d >= 10U) {
-            break;
-        }
-
-        result = result*10 + d;
-        p++;
-    }
-    *ppos = p - format;
-    return result;
-}
-
-// Writes number 'value' in base 'base' into buffer 'buf' of size 'buf_size' bytes.
-// Assumes that buf_size > 0.
-static void format_unsigned(char* buf, size_t buf_size, uint64_t value, int base, bool caps) {
-  char* p = buf;
-  char* end = buf + buf_size - 1;
-
-  // Generate digit string in reverse order.
-  while (value) {
-    unsigned d = value % base;
-    value /= base;
-    if (p != end) {
-      char ch;
-      if (d < 10) {
-        ch = '0' + d;
-      } else {
-        ch = (caps ? 'A' : 'a') + (d - 10);
-      }
-      *p++ = ch;
-    }
-  }
-
-  // Special case for 0.
-  if (p == buf) {
-    if (p != end) {
-      *p++ = '0';
-    }
-  }
-  *p = '\0';
-
-  // Reverse digit string in-place.
-  size_t length = p - buf;
-  for (size_t i = 0, j = length - 1; i < j; ++i, --j) {
-    char ch = buf[i];
-    buf[i] = buf[j];
-    buf[j] = ch;
-  }
-}
-
-static void format_integer(char* buf, size_t buf_size, uint64_t value, char conversion) {
-  // Decode the conversion specifier.
-  int is_signed = (conversion == 'd' || conversion == 'i' || conversion == 'o');
-  int base = 10;
-  if (conversion == 'x' || conversion == 'X') {
-    base = 16;
-  } else if (conversion == 'o') {
-    base = 8;
-  }
-  bool caps = (conversion == 'X');
-
-  if (is_signed && static_cast<int64_t>(value) < 0) {
-    buf[0] = '-';
-    buf += 1;
-    buf_size -= 1;
-    value = static_cast<uint64_t>(-static_cast<int64_t>(value));
-  }
-  format_unsigned(buf, buf_size, value, base, caps);
-}
-
-template <typename Out>
-static void SendRepeat(Out& o, char ch, int count) {
-  char pad[8];
-  memset(pad, ch, sizeof(pad));
-
-  const int pad_size = static_cast<int>(sizeof(pad));
-  while (count > 0) {
-    int avail = count;
-    if (avail > pad_size) {
-      avail = pad_size;
-    }
-    o.Send(pad, avail);
-    count -= avail;
-  }
-}
-
-/* Perform formatted output to an output target 'o' */
-template <typename Out>
-static void out_vformat(Out& o, const char* format, va_list args) {
-    int nn = 0;
-
-    for (;;) {
-        int mm;
-        int padZero = 0;
-        int padLeft = 0;
-        char sign = '\0';
-        int width = -1;
-        int prec  = -1;
-        size_t bytelen = sizeof(int);
-        int slen;
-        char buffer[32];  /* temporary buffer used to format numbers */
-
-        char  c;
-
-        /* first, find all characters that are not 0 or '%' */
-        /* then send them to the output directly */
-        mm = nn;
-        do {
-            c = format[mm];
-            if (c == '\0' || c == '%')
-                break;
-            mm++;
-        } while (1);
-
-        if (mm > nn) {
-            o.Send(format+nn, mm-nn);
-            nn = mm;
-        }
-
-        /* is this it ? then exit */
-        if (c == '\0')
-            break;
-
-        /* nope, we are at a '%' modifier */
-        nn++;  // skip it
-
-        /* parse flags */
-        for (;;) {
-            c = format[nn++];
-            if (c == '\0') {  /* single trailing '%' ? */
-                c = '%';
-                o.Send(&c, 1);
-                return;
-            }
-            else if (c == '0') {
-                padZero = 1;
-                continue;
-            }
-            else if (c == '-') {
-                padLeft = 1;
-                continue;
-            }
-            else if (c == ' ' || c == '+') {
-                sign = c;
-                continue;
-            }
-            break;
-        }
-
-        /* parse field width */
-        if ((c >= '0' && c <= '9')) {
-            nn --;
-            width = static_cast<int>(parse_decimal(format, &nn));
-            c = format[nn++];
-        }
-
-        /* parse precision */
-        if (c == '.') {
-            prec = static_cast<int>(parse_decimal(format, &nn));
-            c = format[nn++];
-        }
-
-        /* length modifier */
-        switch (c) {
-        case 'h':
-            bytelen = sizeof(short);
-            if (format[nn] == 'h') {
-                bytelen = sizeof(char);
-                nn += 1;
-            }
-            c = format[nn++];
-            break;
-        case 'l':
-            bytelen = sizeof(long);
-            if (format[nn] == 'l') {
-                bytelen = sizeof(long long);
-                nn += 1;
-            }
-            c = format[nn++];
-            break;
-        case 'z':
-            bytelen = sizeof(size_t);
-            c = format[nn++];
-            break;
-        case 't':
-            bytelen = sizeof(ptrdiff_t);
-            c = format[nn++];
-            break;
-        default:
-            ;
-        }
-
-        /* conversion specifier */
-        const char* str = buffer;
-        if (c == 's') {
-            /* string */
-            str = va_arg(args, const char*);
-            if (str == NULL) {
-                str = "(null)";
-            }
-        } else if (c == 'c') {
-            /* character */
-            /* NOTE: char is promoted to int when passed through the stack */
-            buffer[0] = static_cast<char>(va_arg(args, int));
-            buffer[1] = '\0';
-        } else if (c == 'p') {
-            uint64_t  value = reinterpret_cast<uintptr_t>(va_arg(args, void*));
-            buffer[0] = '0';
-            buffer[1] = 'x';
-            format_integer(buffer + 2, sizeof(buffer) - 2, value, 'x');
-        } else if (c == 'd' || c == 'i' || c == 'o' || c == 'u' || c == 'x' || c == 'X') {
-            /* integers - first read value from stack */
-            uint64_t value;
-            int is_signed = (c == 'd' || c == 'i' || c == 'o');
-
-            /* NOTE: int8_t and int16_t are promoted to int when passed
-             *       through the stack
-             */
-            switch (bytelen) {
-            case 1: value = static_cast<uint8_t>(va_arg(args, int)); break;
-            case 2: value = static_cast<uint16_t>(va_arg(args, int)); break;
-            case 4: value = va_arg(args, uint32_t); break;
-            case 8: value = va_arg(args, uint64_t); break;
-            default: return;  /* should not happen */
-            }
-
-            /* sign extension, if needed */
-            if (is_signed) {
-                int shift = 64 - 8*bytelen;
-                value = static_cast<uint64_t>((static_cast<int64_t>(value << shift)) >> shift);
-            }
-
-            /* format the number properly into our buffer */
-            format_integer(buffer, sizeof(buffer), value, c);
-        } else if (c == '%') {
-            buffer[0] = '%';
-            buffer[1] = '\0';
-        } else {
-            __assert(__FILE__, __LINE__, "conversion specifier unsupported");
-        }
-
-        /* if we are here, 'str' points to the content that must be
-         * outputted. handle padding and alignment now */
-
-        slen = strlen(str);
-
-        if (sign != '\0' || prec != -1) {
-            __assert(__FILE__, __LINE__, "sign/precision unsupported");
-        }
-
-        if (slen < width && !padLeft) {
-            char padChar = padZero ? '0' : ' ';
-            SendRepeat(o, padChar, width - slen);
-        }
-
-        o.Send(str, slen);
-
-        if (slen < width && padLeft) {
-            char padChar = padZero ? '0' : ' ';
-            SendRepeat(o, padChar, width - slen);
-        }
-    }
-}
-
-int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) {
-  BufferOutputStream os(buffer, buffer_size);
-  va_list args;
-  va_start(args, format);
-  out_vformat(os, format, args);
-  va_end(args);
-  return os.total;
-}
-
-int __libc_format_buffer_va_list(char* buffer, size_t buffer_size, const char* format,
-                                 va_list args) {
-  BufferOutputStream os(buffer, buffer_size);
-  out_vformat(os, format, args);
-  return os.total;
-}
-
-int __libc_format_fd(int fd, const char* format, ...) {
-  FdOutputStream os(fd);
-  va_list args;
-  va_start(args, format);
-  out_vformat(os, format, args);
-  va_end(args);
-  return os.total;
-}
-
-static int __libc_write_stderr(const char* tag, const char* msg) {
-  iovec vec[4];
-  vec[0].iov_base = const_cast<char*>(tag);
-  vec[0].iov_len = strlen(tag);
-  vec[1].iov_base = const_cast<char*>(": ");
-  vec[1].iov_len = 2;
-  vec[2].iov_base = const_cast<char*>(msg);
-  vec[2].iov_len = strlen(msg);
-  vec[3].iov_base = const_cast<char*>("\n");
-  vec[3].iov_len = 1;
-
-  int result = TEMP_FAILURE_RETRY(writev(STDERR_FILENO, vec, 4));
-  return result;
-}
-
-static int __libc_open_log_socket() {
-  // ToDo: Ideally we want this to fail if the gid of the current
-  // process is AID_LOGD, but will have to wait until we have
-  // registered this in private/android_filesystem_config.h. We have
-  // found that all logd crashes thus far have had no problem stuffing
-  // the UNIX domain socket and moving on so not critical *today*.
-
-  int log_fd = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
-  if (log_fd == -1) {
-    return -1;
-  }
-
-  union {
-    struct sockaddr    addr;
-    struct sockaddr_un addrUn;
-  } u;
-  memset(&u, 0, sizeof(u));
-  u.addrUn.sun_family = AF_UNIX;
-  strlcpy(u.addrUn.sun_path, "/dev/socket/logdw", sizeof(u.addrUn.sun_path));
-
-  if (TEMP_FAILURE_RETRY(connect(log_fd, &u.addr, sizeof(u.addrUn))) != 0) {
-    close(log_fd);
-    return -1;
-  }
-
-  return log_fd;
-}
-
-static clockid_t __android_log_clockid() {
-  static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-  ScopedPthreadMutexLocker locker(&mutex);
-
-  static CachedProperty ro_logd_timestamp("ro.logd.timestamp");
-  static CachedProperty persist_logd_timestamp("persist.logd.timestamp");
-
-  char ch = persist_logd_timestamp.Get()[0];
-  if (ch == '\0') ch = ro_logd_timestamp.Get()[0];
-
-  return (tolower(ch) == 'm') ? CLOCK_MONOTONIC : CLOCK_REALTIME;
-}
-
-struct log_time { // Wire format
-  uint32_t tv_sec;
-  uint32_t tv_nsec;
-};
-
-int __libc_write_log(int priority, const char* tag, const char* msg) {
-  int main_log_fd = __libc_open_log_socket();
-  if (main_log_fd == -1) {
-    // Try stderr instead.
-    return __libc_write_stderr(tag, msg);
-  }
-
-  iovec vec[6];
-  char log_id = (priority == ANDROID_LOG_FATAL) ? LOG_ID_CRASH : LOG_ID_MAIN;
-  vec[0].iov_base = &log_id;
-  vec[0].iov_len = sizeof(log_id);
-  uint16_t tid = gettid();
-  vec[1].iov_base = &tid;
-  vec[1].iov_len = sizeof(tid);
-  timespec ts;
-  clock_gettime(__android_log_clockid(), &ts);
-  log_time realtime_ts;
-  realtime_ts.tv_sec = ts.tv_sec;
-  realtime_ts.tv_nsec = ts.tv_nsec;
-  vec[2].iov_base = &realtime_ts;
-  vec[2].iov_len = sizeof(realtime_ts);
-
-  vec[3].iov_base = &priority;
-  vec[3].iov_len = 1;
-  vec[4].iov_base = const_cast<char*>(tag);
-  vec[4].iov_len = strlen(tag) + 1;
-  vec[5].iov_base = const_cast<char*>(msg);
-  vec[5].iov_len = strlen(msg) + 1;
-
-  int result = TEMP_FAILURE_RETRY(writev(main_log_fd, vec, sizeof(vec) / sizeof(vec[0])));
-  close(main_log_fd);
-  return result;
-}
-
-int __libc_format_log_va_list(int priority, const char* tag, const char* format, va_list args) {
-  char buffer[1024];
-  BufferOutputStream os(buffer, sizeof(buffer));
-  out_vformat(os, format, args);
-  return __libc_write_log(priority, tag, buffer);
-}
-
-int __libc_format_log(int priority, const char* tag, const char* format, ...) {
-  va_list args;
-  va_start(args, format);
-  int result = __libc_format_log_va_list(priority, tag, format, args);
-  va_end(args);
-  return result;
-}
-
-static void __libc_fatal_va_list(const char* prefix, const char* format, va_list args) {
-  char msg[1024];
-  BufferOutputStream os(msg, sizeof(msg));
-
-  if (prefix) {
-    os.Send(prefix, strlen(prefix));
-    os.Send(": ", 2);
-  }
-
-  out_vformat(os, format, args);
-
-  // Log to stderr for the benefit of "adb shell" users and gtests.
-  struct iovec iov[2] = {
-    { msg, os.total },
-    { const_cast<char*>("\n"), 1 },
-  };
-  TEMP_FAILURE_RETRY(writev(2, iov, 2));
-
-  // Log to the log for the benefit of regular app developers (whose stdout and stderr are closed).
-  __libc_write_log(ANDROID_LOG_FATAL, "libc", msg);
-
-  android_set_abort_message(msg);
-}
-
-void __libc_fatal(const char* fmt, ...) {
-  va_list args;
-  va_start(args, fmt);
-  __libc_fatal_va_list(nullptr, fmt, args);
-  va_end(args);
-  abort();
-}
-
-void __fortify_fatal(const char* fmt, ...) {
-  va_list args;
-  va_start(args, fmt);
-  __libc_fatal_va_list("FORTIFY", fmt, args);
-  va_end(args);
-  abort();
-}
diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
index 3fceb71..18c998d 100644
--- a/libc/bionic/malloc_common.cpp
+++ b/libc/bionic/malloc_common.cpp
@@ -167,7 +167,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-#include <private/libc_logging.h>
+#include <async_safe/log.h>
 #include <sys/system_properties.h>
 
 extern "C" int __cxa_atexit(void (*func)(void *), void *arg, void *dso);
@@ -188,9 +188,9 @@
 // Log functions
 // =============================================================================
 #define error_log(format, ...)  \
-    __libc_format_log(ANDROID_LOG_ERROR, "libc", (format), ##__VA_ARGS__ )
+    async_safe_format_log(ANDROID_LOG_ERROR, "libc", (format), ##__VA_ARGS__ )
 #define info_log(format, ...)  \
-    __libc_format_log(ANDROID_LOG_INFO, "libc", (format), ##__VA_ARGS__ )
+    async_safe_format_log(ANDROID_LOG_INFO, "libc", (format), ##__VA_ARGS__ )
 // =============================================================================
 
 // =============================================================================
diff --git a/libc/bionic/ndk_cruft.cpp b/libc/bionic/ndk_cruft.cpp
index 29565a2..016b476 100644
--- a/libc/bionic/ndk_cruft.cpp
+++ b/libc/bionic/ndk_cruft.cpp
@@ -46,7 +46,6 @@
 #include <wchar.h>
 
 #include "private/bionic_macros.h"
-#include "private/libc_logging.h"
 
 extern "C" {
 
diff --git a/libc/bionic/new.cpp b/libc/bionic/new.cpp
index 76c46ee..9499ff5 100644
--- a/libc/bionic/new.cpp
+++ b/libc/bionic/new.cpp
@@ -19,14 +19,14 @@
 #include <errno.h>
 #include <stdlib.h>
 
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
 
 const std::nothrow_t std::nothrow = {};
 
 void* operator new(std::size_t size) {
     void* p = malloc(size);
     if (p == NULL) {
-        __libc_fatal("new failed to allocate %zu bytes", size);
+        async_safe_fatal("new failed to allocate %zu bytes", size);
     }
     return p;
 }
@@ -34,7 +34,7 @@
 void* operator new[](std::size_t size) {
     void* p = malloc(size);
     if (p == NULL) {
-        __libc_fatal("new[] failed to allocate %zu bytes", size);
+        async_safe_fatal("new[] failed to allocate %zu bytes", size);
     }
     return p;
 }
diff --git a/libc/bionic/open.cpp b/libc/bionic/open.cpp
index 2daa21f..6d179c4 100644
--- a/libc/bionic/open.cpp
+++ b/libc/bionic/open.cpp
@@ -31,7 +31,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 
-#include "private/libc_logging.h"
+#include "private/bionic_fortify.h"
 
 extern "C" int __openat(int, const char*, int, int);
 
diff --git a/libc/bionic/pthread_attr.cpp b/libc/bionic/pthread_attr.cpp
index cfa58fc..4b6a8f2 100644
--- a/libc/bionic/pthread_attr.cpp
+++ b/libc/bionic/pthread_attr.cpp
@@ -33,9 +33,10 @@
 #include <sys/resource.h>
 #include <unistd.h>
 
+#include <async_safe/log.h>
+
 #include "private/bionic_string_utils.h"
 #include "private/ErrnoRestorer.h"
-#include "private/libc_logging.h"
 #include "pthread_internal.h"
 
 int pthread_attr_init(pthread_attr_t* attr) {
@@ -117,12 +118,12 @@
 static uintptr_t __get_main_stack_startstack() {
   FILE* fp = fopen("/proc/self/stat", "re");
   if (fp == nullptr) {
-    __libc_fatal("couldn't open /proc/self/stat: %s", strerror(errno));
+    async_safe_fatal("couldn't open /proc/self/stat: %s", strerror(errno));
   }
 
   char line[BUFSIZ];
   if (fgets(line, sizeof(line), fp) == nullptr) {
-    __libc_fatal("couldn't read /proc/self/stat: %s", strerror(errno));
+    async_safe_fatal("couldn't read /proc/self/stat: %s", strerror(errno));
   }
 
   fclose(fp);
@@ -138,7 +139,7 @@
              "%*u %*u %*u %*u %*u %*u %*u "
              "%*d %*d %*d %*d %*d %*d "
              "%*u %*u %*d %*u %*u %*u %" SCNuPTR, &startstack) != 1) {
-    __libc_fatal("couldn't parse /proc/self/stat");
+    async_safe_fatal("couldn't parse /proc/self/stat");
   }
 
   return startstack;
@@ -163,7 +164,7 @@
   // Hunt for the region that contains that address.
   FILE* fp = fopen("/proc/self/maps", "re");
   if (fp == nullptr) {
-    __libc_fatal("couldn't open /proc/self/maps");
+    async_safe_fatal("couldn't open /proc/self/maps");
   }
   char line[BUFSIZ];
   while (fgets(line, sizeof(line), fp) != NULL) {
@@ -177,7 +178,7 @@
       }
     }
   }
-  __libc_fatal("Stack not found in /proc/self/maps");
+  async_safe_fatal("Stack not found in /proc/self/maps");
 }
 
 int pthread_attr_getstack(const pthread_attr_t* attr, void** stack_base, size_t* stack_size) {
diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp
index 6b3e148..9f4481f 100644
--- a/libc/bionic/pthread_create.cpp
+++ b/libc/bionic/pthread_create.cpp
@@ -35,11 +35,12 @@
 
 #include "pthread_internal.h"
 
+#include <async_safe/log.h>
+
 #include "private/bionic_macros.h"
 #include "private/bionic_prctl.h"
 #include "private/bionic_ssp.h"
 #include "private/bionic_tls.h"
-#include "private/libc_logging.h"
 #include "private/ErrnoRestorer.h"
 
 // x86 uses segment descriptors rather than a direct pointer to TLS.
@@ -60,13 +61,13 @@
   size_t allocation_size = BIONIC_TLS_SIZE + 2 * PAGE_SIZE;
   void* allocation = mmap(nullptr, allocation_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
   if (allocation == MAP_FAILED) {
-    __libc_fatal("failed to allocate TLS");
+    async_safe_fatal("failed to allocate TLS");
   }
   prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, allocation, allocation_size, "bionic TLS guard page");
 
   thread->bionic_tls = reinterpret_cast<bionic_tls*>(static_cast<char*>(allocation) + PAGE_SIZE);
   if (mprotect(thread->bionic_tls, BIONIC_TLS_SIZE, PROT_READ | PROT_WRITE) != 0) {
-    __libc_fatal("failed to mprotect TLS");
+    async_safe_fatal("failed to mprotect TLS");
   }
   prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, thread->bionic_tls, BIONIC_TLS_SIZE, "bionic TLS");
 }
@@ -118,8 +119,8 @@
       // For backwards compatibility reasons, we only report failures on 64-bit devices.
       error = errno;
 #endif
-      __libc_format_log(ANDROID_LOG_WARN, "libc",
-                        "pthread_create sched_setscheduler call failed: %s", strerror(errno));
+      async_safe_format_log(ANDROID_LOG_WARN, "libc",
+                            "pthread_create sched_setscheduler call failed: %s", strerror(errno));
     }
   }
 
@@ -134,7 +135,7 @@
   int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
   void* space = mmap(NULL, mmap_size, prot, flags, -1, 0);
   if (space == MAP_FAILED) {
-    __libc_format_log(ANDROID_LOG_WARN,
+    async_safe_format_log(ANDROID_LOG_WARN,
                       "libc",
                       "pthread_create failed: couldn't allocate %zu-bytes mapped space: %s",
                       mmap_size, strerror(errno));
@@ -144,9 +145,9 @@
   // Stack is at the lower end of mapped space, stack guard region is at the lower end of stack.
   // Set the stack guard region to PROT_NONE, so we can detect thread stack overflow.
   if (mprotect(space, stack_guard_size, PROT_NONE) == -1) {
-    __libc_format_log(ANDROID_LOG_WARN, "libc",
-                      "pthread_create failed: couldn't mprotect PROT_NONE %zu-byte stack guard region: %s",
-                      stack_guard_size, strerror(errno));
+    async_safe_format_log(ANDROID_LOG_WARN, "libc",
+                          "pthread_create failed: couldn't mprotect PROT_NONE %zu-byte stack guard region: %s",
+                          stack_guard_size, strerror(errno));
     munmap(space, mmap_size);
     return NULL;
   }
@@ -281,7 +282,8 @@
     if (thread->mmap_size != 0) {
       munmap(thread->attr.stack_base, thread->mmap_size);
     }
-    __libc_format_log(ANDROID_LOG_WARN, "libc", "pthread_create failed: clone failed: %s", strerror(errno));
+    async_safe_format_log(ANDROID_LOG_WARN, "libc", "pthread_create failed: clone failed: %s",
+                          strerror(errno));
     return clone_errno;
   }
 
diff --git a/libc/bionic/pthread_internal.cpp b/libc/bionic/pthread_internal.cpp
index 5819bc1..abd403b 100644
--- a/libc/bionic/pthread_internal.cpp
+++ b/libc/bionic/pthread_internal.cpp
@@ -33,10 +33,11 @@
 #include <string.h>
 #include <sys/mman.h>
 
+#include <async_safe/log.h>
+
 #include "private/bionic_futex.h"
 #include "private/bionic_sdk_version.h"
 #include "private/bionic_tls.h"
-#include "private/libc_logging.h"
 
 static pthread_internal_t* g_thread_list = nullptr;
 static pthread_rwlock_t g_thread_list_lock = PTHREAD_RWLOCK_INITIALIZER;
@@ -116,9 +117,9 @@
       // addresses might sometimes contain threads or things that look enough like
       // threads for us to do some real damage by continuing.
       // TODO: try getting rid of this when Treble lets us keep vendor blobs on an old API level.
-      __libc_format_log(ANDROID_LOG_WARN, "libc", "invalid pthread_t (0) passed to libc");
+      async_safe_format_log(ANDROID_LOG_WARN, "libc", "invalid pthread_t (0) passed to libc");
     } else {
-      __libc_fatal("invalid pthread_t %p passed to libc", thread);
+      async_safe_fatal("invalid pthread_t %p passed to libc", thread);
     }
   }
   return nullptr;
diff --git a/libc/bionic/setjmp_cookie.cpp b/libc/bionic/setjmp_cookie.cpp
index 4fa68c2..41a439f 100644
--- a/libc/bionic/setjmp_cookie.cpp
+++ b/libc/bionic/setjmp_cookie.cpp
@@ -34,9 +34,10 @@
 #include <sys/auxv.h>
 #include <sys/cdefs.h>
 
+#include <async_safe/log.h>
+
 #include "private/bionic_arc4random.h"
 #include "private/bionic_globals.h"
-#include "private/libc_logging.h"
 #include "private/KernelArgumentBlock.h"
 
 void __libc_init_setjmp_cookie(libc_globals* globals, KernelArgumentBlock& args) {
@@ -49,7 +50,7 @@
 
 extern "C" __LIBC_HIDDEN__ long __bionic_setjmp_cookie_get(long sigflag) {
   if (sigflag & ~1) {
-    __libc_fatal("unexpected sigflag value: %ld", sigflag);
+    async_safe_fatal("unexpected sigflag value: %ld", sigflag);
   }
 
   return __libc_globals->setjmp_cookie | sigflag;
@@ -58,12 +59,12 @@
 // Aborts if cookie doesn't match, returns the signal flag otherwise.
 extern "C" __LIBC_HIDDEN__ long __bionic_setjmp_cookie_check(long cookie) {
   if (__libc_globals->setjmp_cookie != (cookie & ~1)) {
-    __libc_fatal("setjmp cookie mismatch");
+    async_safe_fatal("setjmp cookie mismatch");
   }
 
   return cookie & 1;
 }
 
 extern "C" __LIBC_HIDDEN__ long __bionic_setjmp_checksum_mismatch() {
-  __libc_fatal("setjmp checksum mismatch");
+  async_safe_fatal("setjmp checksum mismatch");
 }
diff --git a/libc/bionic/strerror_r.cpp b/libc/bionic/strerror_r.cpp
index a0a0809..dad3fb3 100644
--- a/libc/bionic/strerror_r.cpp
+++ b/libc/bionic/strerror_r.cpp
@@ -12,8 +12,9 @@
 #include <signal.h>
 #include <stdio.h>
 
+#include <async_safe/log.h>
+
 #include "private/ErrnoRestorer.h"
-#include "private/libc_logging.h"
 
 struct Pair {
   int code;
@@ -57,7 +58,7 @@
   if (error_name != NULL) {
     length = strlcpy(buf, error_name, buf_len);
   } else {
-    length = __libc_format_buffer(buf, buf_len, "Unknown error %d", error_number);
+    length = async_safe_format_buffer(buf, buf_len, "Unknown error %d", error_number);
   }
   if (length >= buf_len) {
     errno_restorer.override(ERANGE);
diff --git a/libc/bionic/syslog.cpp b/libc/bionic/syslog.cpp
index 8e3f34f..9424573 100644
--- a/libc/bionic/syslog.cpp
+++ b/libc/bionic/syslog.cpp
@@ -19,7 +19,7 @@
 #include <string.h>
 #include <syslog.h>
 
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
 
 static const char* syslog_log_tag = NULL;
 static int syslog_priority_mask = 0xff;
@@ -109,7 +109,7 @@
     *dst = '\0';
   }
 
-  // We can't let __libc_format_log do the formatting because it doesn't support
+  // We can't let async_safe_format_log do the formatting because it doesn't support
   // all the printf functionality.
   char log_line[1024];
   vsnprintf(log_line, sizeof(log_line), log_fmt, args);
@@ -118,5 +118,5 @@
     free(const_cast<char*>(log_fmt));
   }
 
-  __libc_format_log(android_log_priority, log_tag, "%s", log_line);
+  async_safe_format_log(android_log_priority, log_tag, "%s", log_line);
 }
diff --git a/libc/bionic/system_properties.cpp b/libc/bionic/system_properties.cpp
index 9fb03ac..a958699 100644
--- a/libc/bionic/system_properties.cpp
+++ b/libc/bionic/system_properties.cpp
@@ -54,12 +54,13 @@
 #include <sys/_system_properties.h>
 #include <sys/system_properties.h>
 
+#include <async_safe/log.h>
+
 #include "private/ErrnoRestorer.h"
 #include "private/bionic_futex.h"
 #include "private/bionic_lock.h"
 #include "private/bionic_macros.h"
 #include "private/bionic_sdk_version.h"
-#include "private/libc_logging.h"
 
 static constexpr int PROP_FILENAME_MAX = 1024;
 
@@ -227,8 +228,8 @@
 
   if (context) {
     if (fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1, 0) != 0) {
-      __libc_format_log(ANDROID_LOG_ERROR, "libc",
-                        "fsetxattr failed to set context (%s) for \"%s\"", context, filename);
+      async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+                            "fsetxattr failed to set context (%s) for \"%s\"", context, filename);
       /*
        * fsetxattr() will fail during system properties tests due to selinux policy.
        * We do not want to create a custom policy for the tester, so we will continue in
@@ -640,9 +641,9 @@
       // ms so callers who do read-after-write can reliably see
       // what they've written.  Most of the time.
       // TODO: fix the system properties design.
-      __libc_format_log(ANDROID_LOG_WARN, "libc",
-                        "Property service has timed out while trying to set \"%s\" to \"%s\"",
-                        msg->name, msg->value);
+      async_safe_format_log(ANDROID_LOG_WARN, "libc",
+                            "Property service has timed out while trying to set \"%s\" to \"%s\"",
+                            msg->name, msg->value);
       result = 0;
     }
   }
@@ -806,7 +807,8 @@
   }
 
   char filename[PROP_FILENAME_MAX];
-  int len = __libc_format_buffer(filename, sizeof(filename), "%s/%s", property_filename, context_);
+  int len = async_safe_format_buffer(filename, sizeof(filename), "%s/%s", property_filename,
+                                     context_);
   if (len < 0 || len > PROP_FILENAME_MAX) {
     lock_.unlock();
     return false;
@@ -841,7 +843,8 @@
 
 bool context_node::check_access() {
   char filename[PROP_FILENAME_MAX];
-  int len = __libc_format_buffer(filename, sizeof(filename), "%s/%s", property_filename, context_);
+  int len = async_safe_format_buffer(filename, sizeof(filename), "%s/%s", property_filename,
+                                     context_);
   if (len < 0 || len > PROP_FILENAME_MAX) {
     return false;
   }
@@ -864,7 +867,8 @@
 static bool map_system_property_area(bool access_rw, bool* fsetxattr_failed) {
   char filename[PROP_FILENAME_MAX];
   int len =
-      __libc_format_buffer(filename, sizeof(filename), "%s/properties_serial", property_filename);
+      async_safe_format_buffer(filename, sizeof(filename), "%s/properties_serial",
+                               property_filename);
   if (len < 0 || len > PROP_FILENAME_MAX) {
     __system_property_area__ = nullptr;
     return false;
@@ -1152,7 +1156,7 @@
 
   prop_area* pa = get_prop_area_for_name(name);
   if (!pa) {
-    __libc_format_log(ANDROID_LOG_ERROR, "libc", "Access denied finding property \"%s\"", name);
+    async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Access denied finding property \"%s\"", name);
     return nullptr;
   }
 
@@ -1184,11 +1188,11 @@
       if (name != nullptr) {
         size_t namelen = strlcpy(name, pi->name, PROP_NAME_MAX);
         if (namelen >= PROP_NAME_MAX) {
-          __libc_format_log(ANDROID_LOG_ERROR, "libc",
-                            "The property name length for \"%s\" is >= %d;"
-                            " please use __system_property_read_callback"
-                            " to read this property. (the name is truncated to \"%s\")",
-                            pi->name, PROP_NAME_MAX - 1, name);
+          async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+                                "The property name length for \"%s\" is >= %d;"
+                                " please use __system_property_read_callback"
+                                " to read this property. (the name is truncated to \"%s\")",
+                                pi->name, PROP_NAME_MAX - 1, name);
         }
       }
       return len;
@@ -1239,17 +1243,17 @@
   char value[PROP_VALUE_MAX];
   if (__system_property_get(kServiceVersionPropertyName, value) == 0) {
     g_propservice_protocol_version = kProtocolVersion1;
-    __libc_format_log(ANDROID_LOG_WARN, "libc",
-                      "Using old property service protocol (\"%s\" is not set)",
-                      kServiceVersionPropertyName);
+    async_safe_format_log(ANDROID_LOG_WARN, "libc",
+                          "Using old property service protocol (\"%s\" is not set)",
+                          kServiceVersionPropertyName);
   } else {
     uint32_t version = static_cast<uint32_t>(atoll(value));
     if (version >= kProtocolVersion2) {
       g_propservice_protocol_version = kProtocolVersion2;
     } else {
-      __libc_format_log(ANDROID_LOG_WARN, "libc",
-                        "Using old property service protocol (\"%s\"=\"%s\")",
-                        kServiceVersionPropertyName, value);
+      async_safe_format_log(ANDROID_LOG_WARN, "libc",
+                            "Using old property service protocol (\"%s\"=\"%s\")",
+                            kServiceVersionPropertyName, value);
       g_propservice_protocol_version = kProtocolVersion1;
     }
   }
@@ -1280,49 +1284,49 @@
     PropertyServiceConnection connection;
     if (!connection.IsValid()) {
       errno = connection.GetLastError();
-      __libc_format_log(ANDROID_LOG_WARN,
-                        "libc",
-                        "Unable to set property \"%s\" to \"%s\": connection failed; errno=%d (%s)",
-                        key,
-                        value,
-                        errno,
-                        strerror(errno));
+      async_safe_format_log(ANDROID_LOG_WARN,
+                            "libc",
+                            "Unable to set property \"%s\" to \"%s\": connection failed; errno=%d (%s)",
+                            key,
+                            value,
+                            errno,
+                            strerror(errno));
       return -1;
     }
 
     SocketWriter writer(&connection);
     if (!writer.WriteUint32(PROP_MSG_SETPROP2).WriteString(key).WriteString(value).Send()) {
       errno = connection.GetLastError();
-      __libc_format_log(ANDROID_LOG_WARN,
-                        "libc",
-                        "Unable to set property \"%s\" to \"%s\": write failed; errno=%d (%s)",
-                        key,
-                        value,
-                        errno,
-                        strerror(errno));
+      async_safe_format_log(ANDROID_LOG_WARN,
+                            "libc",
+                            "Unable to set property \"%s\" to \"%s\": write failed; errno=%d (%s)",
+                            key,
+                            value,
+                            errno,
+                            strerror(errno));
       return -1;
     }
 
     int result = -1;
     if (!connection.RecvInt32(&result)) {
       errno = connection.GetLastError();
-      __libc_format_log(ANDROID_LOG_WARN,
-                        "libc",
-                        "Unable to set property \"%s\" to \"%s\": recv failed; errno=%d (%s)",
-                        key,
-                        value,
-                        errno,
-                        strerror(errno));
+      async_safe_format_log(ANDROID_LOG_WARN,
+                            "libc",
+                            "Unable to set property \"%s\" to \"%s\": recv failed; errno=%d (%s)",
+                            key,
+                            value,
+                            errno,
+                            strerror(errno));
       return -1;
     }
 
     if (result != PROP_SUCCESS) {
-      __libc_format_log(ANDROID_LOG_WARN,
-                        "libc",
-                        "Unable to set property \"%s\" to \"%s\": error code: 0x%x",
-                        key,
-                        value,
-                        result);
+      async_safe_format_log(ANDROID_LOG_WARN,
+                            "libc",
+                            "Unable to set property \"%s\" to \"%s\": error code: 0x%x",
+                            key,
+                            value,
+                            result);
       return -1;
     }
 
@@ -1377,7 +1381,7 @@
   prop_area* pa = get_prop_area_for_name(name);
 
   if (!pa) {
-    __libc_format_log(ANDROID_LOG_ERROR, "libc", "Access denied adding property \"%s\"", name);
+    async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Access denied adding property \"%s\"", name);
     return -1;
   }
 
diff --git a/libc/dns/resolv/res_cache.c b/libc/dns/resolv/res_cache.c
index 82e0ddf..9c65570 100644
--- a/libc/dns/resolv/res_cache.c
+++ b/libc/dns/resolv/res_cache.c
@@ -47,7 +47,7 @@
 #include "resolv_netid.h"
 #include "res_private.h"
 
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
 
 /* This code implements a small and *simple* DNS resolver cache.
  *
@@ -155,7 +155,7 @@
 
 #define XLOG(...) ({ \
     if (DEBUG) { \
-        __libc_format_log(ANDROID_LOG_DEBUG,"libc",__VA_ARGS__); \
+        async_safe_format_log(ANDROID_LOG_DEBUG,"libc",__VA_ARGS__); \
     } else { \
         ((void)0); \
     } \
diff --git a/libc/dns/resolv/res_send.c b/libc/dns/resolv/res_send.c
index f53da5f..586bb8f 100644
--- a/libc/dns/resolv/res_send.c
+++ b/libc/dns/resolv/res_send.c
@@ -114,7 +114,7 @@
 
 #include <resolv_cache.h>
 
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
 
 #ifndef DE_CONST
 #define DE_CONST(c,v)   v = ((c) ? \
@@ -564,7 +564,7 @@
 			}
 
 			if (DBG) {
-				__libc_format_log(ANDROID_LOG_DEBUG, "libc",
+				async_safe_format_log(ANDROID_LOG_DEBUG, "libc",
 					"used send_vc %d\n", n);
 			}
 
@@ -576,7 +576,7 @@
 		} else {
 			/* Use datagrams. */
 			if (DBG) {
-				__libc_format_log(ANDROID_LOG_DEBUG, "libc", "using send_dg\n");
+				async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "using send_dg\n");
 			}
 
 			n = send_dg(statp, buf, buflen, ans, anssiz, &terrno,
@@ -591,7 +591,7 @@
 			}
 
 			if (DBG) {
-				__libc_format_log(ANDROID_LOG_DEBUG, "libc", "used send_dg %d\n",n);
+				async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "used send_dg %d\n",n);
 			}
 
 			if (n < 0)
@@ -599,7 +599,7 @@
 			if (n == 0)
 				goto next_ns;
 			if (DBG) {
-				__libc_format_log(ANDROID_LOG_DEBUG, "libc", "time=%ld\n",
+				async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "time=%ld\n",
 						  time(NULL));
 			}
 			if (v_circuit)
@@ -739,7 +739,7 @@
 		timeout = 1;
 	}
 	if (DBG) {
-		__libc_format_log(ANDROID_LOG_DEBUG, "libc", "using timeout of %d sec\n", timeout);
+		async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "using timeout of %d sec\n", timeout);
 	}
 
 	return timeout;
@@ -764,7 +764,7 @@
 	void *tmp;
 
 	if (DBG) {
-		__libc_format_log(ANDROID_LOG_DEBUG, "libc", "using send_vc\n");
+		async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "using send_vc\n");
 	}
 
 	nsap = get_nsaddr(statp, (size_t)ns);
@@ -993,7 +993,7 @@
 		timeout = evConsTime((long)sec, 0L);
 		finish = evAddTime(now, timeout);
 		if (DBG) {
-			__libc_format_log(ANDROID_LOG_DEBUG, "libc", "  %d send_vc\n", sock);
+			async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "  %d send_vc\n", sock);
 		}
 
 		res = retrying_select(sock, &rset, &wset, &finish);
@@ -1004,7 +1004,7 @@
 done:
 	fcntl(sock, F_SETFL, origflags);
 	if (DBG) {
-		__libc_format_log(ANDROID_LOG_DEBUG, "libc",
+		async_safe_format_log(ANDROID_LOG_DEBUG, "libc",
 			"  %d connect_with_timeout returning %d\n", sock, res);
 	}
 	return res;
@@ -1020,7 +1020,7 @@
 
 retry:
 	if (DBG) {
-		__libc_format_log(ANDROID_LOG_DEBUG, "libc", "  %d retrying_select\n", sock);
+		async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "  %d retrying_select\n", sock);
 	}
 
 	now = evNowTime();
@@ -1040,7 +1040,7 @@
 	n = pselect(sock + 1, readset, writeset, NULL, &timeout, NULL);
 	if (n == 0) {
 		if (DBG) {
-			__libc_format_log(ANDROID_LOG_DEBUG, " libc",
+			async_safe_format_log(ANDROID_LOG_DEBUG, " libc",
 				"  %d retrying_select timeout\n", sock);
 		}
 		errno = ETIMEDOUT;
@@ -1050,7 +1050,7 @@
 		if (errno == EINTR)
 			goto retry;
 		if (DBG) {
-			__libc_format_log(ANDROID_LOG_DEBUG, "libc",
+			async_safe_format_log(ANDROID_LOG_DEBUG, "libc",
 				"  %d retrying_select got error %d\n",sock, n);
 		}
 		return n;
@@ -1060,7 +1060,7 @@
 		if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len) < 0 || error) {
 			errno = error;
 			if (DBG) {
-				__libc_format_log(ANDROID_LOG_DEBUG, "libc",
+				async_safe_format_log(ANDROID_LOG_DEBUG, "libc",
 					"  %d retrying_select dot error2 %d\n", sock, errno);
 			}
 
@@ -1068,7 +1068,7 @@
 		}
 	}
 	if (DBG) {
-		__libc_format_log(ANDROID_LOG_DEBUG, "libc",
+		async_safe_format_log(ANDROID_LOG_DEBUG, "libc",
 			"  %d retrying_select returning %d\n",sock, n);
 	}
 
diff --git a/libc/dns/resolv/res_state.c b/libc/dns/resolv/res_state.c
index 4ed168c..94124ff 100644
--- a/libc/dns/resolv/res_state.c
+++ b/libc/dns/resolv/res_state.c
@@ -41,9 +41,9 @@
 #define DEBUG 0
 
 #if DEBUG
-#  include "private/libc_logging.h"
+#  include <async_safe/log.h>
 #  include <unistd.h>  /* for gettid() */
-#  define D(...) __libc_format_log(ANDROID_LOG_DEBUG,"libc", __VA_ARGS__)
+#  define D(...) async_safe_format_log(ANDROID_LOG_DEBUG,"libc", __VA_ARGS__)
 #else
 #  define D(...)  do{}while(0)
 #endif
diff --git a/libc/dns/resolv/res_stats.c b/libc/dns/resolv/res_stats.c
index 99c79e4..97d54d2 100644
--- a/libc/dns/resolv/res_stats.c
+++ b/libc/dns/resolv/res_stats.c
@@ -18,9 +18,10 @@
 #include <arpa/nameser.h>
 #include <string.h>
 
-#include "resolv_stats.h"
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
+
 #include "isc/eventlib.h"
+#include "resolv_stats.h"
 
 #define DBG 0
 
@@ -38,7 +39,7 @@
 _res_stats_set_sample(struct __res_sample* sample, time_t now, int rcode, int rtt)
 {
     if (DBG) {
-        __libc_format_log(ANDROID_LOG_INFO, "libc", "rcode = %d, sec = %d", rcode, rtt);
+        async_safe_format_log(ANDROID_LOG_INFO, "libc", "rcode = %d, sec = %d", rcode, rtt);
     }
     sample->at = now;
     sample->rcode = rcode;
@@ -128,14 +129,15 @@
     if (successes >= 0 && errors >= 0 && timeouts >= 0) {
         int total = successes + errors + timeouts;
         if (DBG) {
-            __libc_format_log(ANDROID_LOG_DEBUG, "libc", "NS stats: S %d + E %d + T %d + I %d "
+            async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "NS stats: S %d + E %d + T %d + I %d "
                  "= %d, rtt = %d, min_samples = %d\n", successes, errors, timeouts, internal_errors,
                  total, rtt_avg, params->min_samples);
         }
         if (total >= params->min_samples && (errors > 0 || timeouts > 0)) {
             int success_rate = successes * 100 / total;
             if (DBG) {
-                __libc_format_log(ANDROID_LOG_DEBUG, "libc", "success rate %d%%\n", success_rate);
+                async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "success rate %d%%\n",
+                                      success_rate);
             }
             if (success_rate < params->success_threshold) {
                 // evNowTime() is used here instead of time() to stay consistent with the rest of
@@ -146,13 +148,13 @@
                     // date has been reached, however the code for returning the ring buffer to its
                     // previous non-circular state would induce additional complexity.
                     if (DBG) {
-                        __libc_format_log(ANDROID_LOG_INFO, "libc",
+                        async_safe_format_log(ANDROID_LOG_INFO, "libc",
                             "samples stale, retrying server\n");
                     }
                     _res_stats_clear_samples(stats);
                 } else {
                     if (DBG) {
-                        __libc_format_log(ANDROID_LOG_INFO, "libc",
+                        async_safe_format_log(ANDROID_LOG_INFO, "libc",
                             "too many resolution errors, ignoring server\n");
                     }
                     return 0;
diff --git a/libc/include/android/legacy_signal_inlines.h b/libc/include/android/legacy_signal_inlines.h
index afdaca8..a5d3a6f 100644
--- a/libc/include/android/legacy_signal_inlines.h
+++ b/libc/include/android/legacy_signal_inlines.h
@@ -41,6 +41,25 @@
 
 #if __ANDROID_API__ < __ANDROID_API_L__
 
+/* These weren't introduced until L. */
+int __libc_current_sigrtmax() __attribute__((__weak__)) __VERSIONER_NO_GUARD;
+int __libc_current_sigrtmin() __attribute__((__weak__)) __VERSIONER_NO_GUARD;
+
+static __inline int __ndk_legacy___libc_current_sigrtmax() {
+  if (__libc_current_sigrtmax) return __libc_current_sigrtmax();
+  return __SIGRTMAX; /* Should match __libc_current_sigrtmax. */
+}
+
+static __inline int __ndk_legacy___libc_current_sigrtmin() {
+  if (__libc_current_sigrtmin) return __libc_current_sigrtmin();
+  return __SIGRTMIN + 4; /* Should match __libc_current_sigrtmin. */
+}
+
+#undef SIGRTMAX
+#define SIGRTMAX __ndk_legacy___libc_current_sigrtmax()
+#undef SIGRTMIN
+#define SIGRTMIN __ndk_legacy___libc_current_sigrtmin()
+
 static __inline int sigismember(const sigset_t *set, int signum) {
   /* Signal numbers start at 1, but bit positions start at 0. */
   int bit = signum - 1;
diff --git a/libc/include/elf.h b/libc/include/elf.h
index c36bc8d..4181006 100644
--- a/libc/include/elf.h
+++ b/libc/include/elf.h
@@ -184,6 +184,12 @@
 
 #define PT_GNU_RELRO 0x6474e552
 
+#undef ELF_ST_TYPE
+#define ELF_ST_TYPE(x) ((x) & 0xf)
+#define ELF_ST_INFO(b,t) (((b) << 4) + ((t) & 0xf))
+#define ELF32_ST_INFO(b,t) ELF_ST_INFO(b,t)
+#define ELF64_ST_INFO(b,t) ELF_ST_INFO(b,t)
+
 #define STB_LOOS      10
 #define STB_HIOS      12
 #define STB_LOPROC    13
diff --git a/libc/include/malloc.h b/libc/include/malloc.h
index 752ee72..412e3f0 100644
--- a/libc/include/malloc.h
+++ b/libc/include/malloc.h
@@ -23,13 +23,9 @@
 
 __BEGIN_DECLS
 
-#if defined(__clang__)
-/* clang should support alloc_size in the nearish future. */
-#if __has_attribute(alloc_size)
-#error "We should enable alloc_size for clang."
-#else
+// Remove the workaround once b/37423073 is fixed.
+#if defined(__clang__) && !__has_attribute(alloc_size)
 #define __BIONIC_ALLOC_SIZE(...)
-#endif
 #else
 #define __BIONIC_ALLOC_SIZE(...) __attribute__((__alloc_size__(__VA_ARGS__)))
 #endif
diff --git a/libc/kernel/tools/defaults.py b/libc/kernel/tools/defaults.py
index 620bb31..c22f684 100644
--- a/libc/kernel/tools/defaults.py
+++ b/libc/kernel/tools/defaults.py
@@ -26,6 +26,9 @@
     "CONFIG_64BIT": "__LP64__",
     "CONFIG_X86_32": "__i386__",
     "__EXPORTED_HEADERS__": "1",
+    "__HAVE_BUILTIN_BSWAP16__": "1",
+    "__HAVE_BUILTIN_BSWAP32__": "1",
+    "__HAVE_BUILTIN_BSWAP64__": "1",
     }
 
 # define to true if you want to remove all defined(CONFIG_FOO) tests
@@ -77,14 +80,14 @@
     "udphdr": "__kernel_udphdr",
     # The kernel's struct epoll_event just has __u64 for the data.
     "epoll_event": "__kernel_uapi_epoll_event",
+    # This causes problems when trying to export the headers for the ndk.
+    "__attribute_const__": "__attribute__((__const__))",
     }
 
-# this is the set of known static inline functions that we want to keep
-# in the final ARM headers. this is only used to keep optimized byteswapping
-# static functions and stuff like that.
-# TODO: this isn't working!
+# This is the set of known static inline functions that we want to keep
+# in the final kernel headers.
 kernel_known_arm_statics = set(
-        [ "___arch__swab32",    # asm-arm/byteorder.h
+        [
         ]
     )
 
@@ -99,8 +102,7 @@
     )
 
 kernel_known_x86_statics = set(
-        [ "___arch__swab32",  # asm-x86/byteorder.h
-          "___arch__swab64",  # asm-x86/byteorder.h
+        [
         ]
     )
 
@@ -108,6 +110,26 @@
         [
           "ipt_get_target",  # uapi/linux/netfilter_ipv4/ip_tables.h
           "ip6t_get_target", # uapi/linux/netfilter_ipv6/ip6_tables.h
+          # Byte swapping inlines from uapi/linux/swab.h
+          # The below functions are the ones we are guaranting we export.
+          "__swab16",
+          "__swab32",
+          "__swab64",
+          "__swab16p",
+          "__swab32p",
+          "__swab64p",
+          "__swab16s",
+          "__swab32s",
+          "__swab64s",
+          "__swahw32",
+          "__swahb32",
+          "__swahw32p",
+          "__swahb32p",
+          "__swahw32s",
+          "__swahb32s",
+          # These are required to support the above functions.
+          "__fswahw32",
+          "__fswahb32",
         ]
     )
 
diff --git a/libc/kernel/uapi/linux/swab.h b/libc/kernel/uapi/linux/swab.h
index a3387de..71aac11 100644
--- a/libc/kernel/uapi/linux/swab.h
+++ b/libc/kernel/uapi/linux/swab.h
@@ -41,70 +41,115 @@
 #else
 #endif
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+static inline __attribute__((__const__)) __u32 __fswahw32(__u32 val) {
 #ifdef __arch_swahw32
+  return __arch_swahw32(val);
 #else
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  return ___constant_swahw32(val);
 #endif
+}
+static inline __attribute__((__const__)) __u32 __fswahb32(__u32 val) {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #ifdef __arch_swahb32
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  return __arch_swahb32(val);
 #else
+  return ___constant_swahb32(val);
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #endif
-#ifdef __HAVE_BUILTIN_BSWAP16__
+}
 #define __swab16(x) (__u16) __builtin_bswap16((__u16) (x))
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
-#else
-#define __swab16(x) (__builtin_constant_p((__u16) (x)) ? ___constant_swab16(x) : __fswab16(x))
-#endif
-#ifdef __HAVE_BUILTIN_BSWAP32__
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define __swab32(x) (__u32) __builtin_bswap32((__u32) (x))
-#else
-#define __swab32(x) (__builtin_constant_p((__u32) (x)) ? ___constant_swab32(x) : __fswab32(x))
-#endif
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
-#ifdef __HAVE_BUILTIN_BSWAP64__
 #define __swab64(x) (__u64) __builtin_bswap64((__u64) (x))
-#else
-#define __swab64(x) (__builtin_constant_p((__u64) (x)) ? ___constant_swab64(x) : __fswab64(x))
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
-#endif
 #define __swahw32(x) (__builtin_constant_p((__u32) (x)) ? ___constant_swahw32(x) : __fswahw32(x))
 #define __swahb32(x) (__builtin_constant_p((__u32) (x)) ? ___constant_swahb32(x) : __fswahb32(x))
+static __always_inline __u16 __swab16p(const __u16 * p) {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #ifdef __arch_swab16p
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  return __arch_swab16p(p);
 #else
+  return __swab16(* p);
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #endif
+}
+static __always_inline __u32 __swab32p(const __u32 * p) {
 #ifdef __arch_swab32p
-#else
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  return __arch_swab32p(p);
+#else
+  return __swab32(* p);
 #endif
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+}
+static __always_inline __u64 __swab64p(const __u64 * p) {
 #ifdef __arch_swab64p
-#else
-#endif
+  return __arch_swab64p(p);
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#else
+  return __swab64(* p);
+#endif
+}
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+static inline __u32 __swahw32p(const __u32 * p) {
 #ifdef __arch_swahw32p
+  return __arch_swahw32p(p);
 #else
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  return __swahw32(* p);
 #endif
+}
+static inline __u32 __swahb32p(const __u32 * p) {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #ifdef __arch_swahb32p
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  return __arch_swahb32p(p);
 #else
+  return __swahb32(* p);
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #endif
+}
+static inline void __swab16s(__u16 * p) {
 #ifdef __arch_swab16s
-#else
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  __arch_swab16s(p);
+#else
+  * p = __swab16p(p);
 #endif
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+}
+static __always_inline void __swab32s(__u32 * p) {
 #ifdef __arch_swab32s
-#else
-#endif
+  __arch_swab32s(p);
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#else
+  * p = __swab32p(p);
+#endif
+}
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+static __always_inline void __swab64s(__u64 * p) {
 #ifdef __arch_swab64s
+  __arch_swab64s(p);
 #else
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  * p = __swab64p(p);
 #endif
+}
+static inline void __swahw32s(__u32 * p) {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #ifdef __arch_swahw32s
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  __arch_swahw32s(p);
 #else
+  * p = __swahw32p(p);
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #endif
+}
+static inline void __swahb32s(__u32 * p) {
 #ifdef __arch_swahb32s
-#else
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  __arch_swahb32s(p);
+#else
+  * p = __swahb32p(p);
 #endif
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+}
 #endif
diff --git a/libc/malloc_debug/Android.bp b/libc/malloc_debug/Android.bp
index 708c101..b071b90 100644
--- a/libc/malloc_debug/Android.bp
+++ b/libc/malloc_debug/Android.bp
@@ -13,9 +13,10 @@
 
     stl: "libc++_static",
 
-    static_libs: ["libc_logging"],
+    whole_static_libs: ["libasync_safe"],
 
     include_dirs: ["bionic/libc"],
+
     export_include_dirs: ["."],
 
     sanitize: {
@@ -29,7 +30,6 @@
         "-Werror",
         "-Wno-error=format-zero-length",
     ],
-
 }
 
 // ==============================================================
@@ -61,9 +61,9 @@
     },
 
     static_libs: [
+        "libasync_safe",
         "libbase",
         "libc_malloc_debug_backtrace",
-        "libc_logging",
     ],
 
     multilib: {
@@ -89,7 +89,6 @@
         "-fno-stack-protector",
         "-Wno-error=format-zero-length",
     ],
-
 }
 
 // ==============================================================
@@ -118,7 +117,7 @@
     whole_static_libs: ["libc_malloc_debug"],
 
     local_include_dirs: ["tests"],
-    include_dirs: ["bionic/libc"],
+    include_dirs: ["bionic/libc", "bionic/libc/async_safe/include"],
 
     shared_libs: ["libbase"],
 
@@ -127,5 +126,4 @@
         "-Werror",
         "-Wno-error=format-zero-length",
     ],
-
 }
diff --git a/libc/malloc_debug/backtrace.cpp b/libc/malloc_debug/backtrace.cpp
index 75a255c..88f5a1d 100644
--- a/libc/malloc_debug/backtrace.cpp
+++ b/libc/malloc_debug/backtrace.cpp
@@ -158,13 +158,13 @@
       char* demangled_symbol = __cxa_demangle(symbol, nullptr, nullptr, nullptr);
       const char* best_name = (demangled_symbol != nullptr) ? demangled_symbol : symbol;
 
-      __libc_format_buffer(buf, sizeof(buf),
-          "          #%02zd  pc %" PAD_PTR "  %s (%s+%" PRIuPTR ")\n", frame_num,
+      async_safe_format_buffer(
+          buf, sizeof(buf), "          #%02zd  pc %" PAD_PTR "  %s (%s+%" PRIuPTR ")\n", frame_num,
           rel_pc, soname, best_name, frames[frame_num] - offset);
       free(demangled_symbol);
     } else {
-      __libc_format_buffer(buf, sizeof(buf),
-          "          #%02zd  pc %" PAD_PTR "  %s\n", frame_num, rel_pc, soname);
+      async_safe_format_buffer(
+          buf, sizeof(buf), "          #%02zd  pc %" PAD_PTR "  %s\n", frame_num, rel_pc, soname);
     }
     str += buf;
   }
diff --git a/libc/malloc_debug/debug_log.h b/libc/malloc_debug/debug_log.h
index 4df0408..ed4b541 100644
--- a/libc/malloc_debug/debug_log.h
+++ b/libc/malloc_debug/debug_log.h
@@ -29,18 +29,18 @@
 #ifndef MALLOC_DEBUG_LOG_H
 #define MALLOC_DEBUG_LOG_H
 
-#include <private/libc_logging.h>
+#include <async_safe/log.h>
 
 // =============================================================================
 // log functions
 // =============================================================================
 #define debug_log(format, ...)  \
-    __libc_format_log(ANDROID_LOG_DEBUG, "malloc_debug", (format), ##__VA_ARGS__ )
+    async_safe_format_log(ANDROID_LOG_DEBUG, "malloc_debug", (format), ##__VA_ARGS__ )
 #define error_log(format, ...)  \
-    __libc_format_log(ANDROID_LOG_ERROR, "malloc_debug", (format), ##__VA_ARGS__ )
+    async_safe_format_log(ANDROID_LOG_ERROR, "malloc_debug", (format), ##__VA_ARGS__ )
 #define error_log_string(str)  \
-    __libc_write_log(ANDROID_LOG_ERROR, "malloc_debug", (str))
+    async_safe_write_log(ANDROID_LOG_ERROR, "malloc_debug", (str))
 #define info_log(format, ...)  \
-    __libc_format_log(ANDROID_LOG_INFO, "malloc_debug", (format), ##__VA_ARGS__ )
+    async_safe_format_log(ANDROID_LOG_INFO, "malloc_debug", (format), ##__VA_ARGS__ )
 
 #endif  // MALLOC_DEBUG_LOG_H
diff --git a/libc/malloc_debug/tests/log_fake.cpp b/libc/malloc_debug/tests/log_fake.cpp
index 194d42b..fb64e3e 100644
--- a/libc/malloc_debug/tests/log_fake.cpp
+++ b/libc/malloc_debug/tests/log_fake.cpp
@@ -44,7 +44,7 @@
   return g_fake_log_print;
 }
 
-extern "C" int __libc_format_log(int priority, const char* tag, const char* format, ...) {
+extern "C" int async_safe_format_log(int priority, const char* tag, const char* format, ...) {
   g_fake_log_print += std::to_string(priority) + ' ';
   g_fake_log_print += tag;
   g_fake_log_print += ' ';
diff --git a/libc/private/WriteProtected.h b/libc/private/WriteProtected.h
index 1133e2a..20afdec 100644
--- a/libc/private/WriteProtected.h
+++ b/libc/private/WriteProtected.h
@@ -23,9 +23,10 @@
 #include <sys/mman.h>
 #include <sys/user.h>
 
+#include <async_safe/log.h>
+
 #include "private/bionic_macros.h"
 #include "private/bionic_prctl.h"
-#include "private/libc_logging.h"
 
 template <typename T>
 union WriteProtectedContents {
@@ -57,7 +58,7 @@
     memset(&contents, 0, sizeof(contents));
 
     if (mprotect(&contents, PAGE_SIZE, PROT_READ)) {
-      __libc_fatal("failed to make WriteProtected nonwritable in initialize");
+      async_safe_fatal("failed to make WriteProtected nonwritable in initialize");
     }
   }
 
@@ -72,13 +73,13 @@
   template <typename Mutator>
   void mutate(Mutator mutator) {
     if (mprotect(&contents, PAGE_SIZE, PROT_READ | PROT_WRITE) != 0) {
-      __libc_fatal("failed to make WriteProtected writable in mutate: %s",
-                   strerror(errno));
+      async_safe_fatal("failed to make WriteProtected writable in mutate: %s",
+                       strerror(errno));
     }
     mutator(&contents.value);
     if (mprotect(&contents, PAGE_SIZE, PROT_READ) != 0) {
-      __libc_fatal("failed to make WriteProtected nonwritable in mutate: %s",
-                   strerror(errno));
+      async_safe_fatal("failed to make WriteProtected nonwritable in mutate: %s",
+                       strerror(errno));
     }
   }
 };
diff --git a/libc/private/bionic_fortify.h b/libc/private/bionic_fortify.h
index df810ca..8591117 100644
--- a/libc/private/bionic_fortify.h
+++ b/libc/private/bionic_fortify.h
@@ -26,11 +26,21 @@
  * SUCH DAMAGE.
  */
 
-#include "private/libc_logging.h"
-
 #include <poll.h> // For struct pollfd.
+#include <stdarg.h>
+#include <stdlib.h>
 #include <sys/select.h> // For struct fd_set.
 
+#include <async_safe/log.h>
+
+static inline __noreturn void __fortify_fatal(const char* fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+  async_safe_fatal_va_list("FORTIFY", fmt, args);
+  va_end(args);
+  abort();
+}
+
 //
 // Common helpers.
 //
diff --git a/libc/stdio/stdio_ext.cpp b/libc/stdio/stdio_ext.cpp
index f2f58c6..ebc705c 100644
--- a/libc/stdio/stdio_ext.cpp
+++ b/libc/stdio/stdio_ext.cpp
@@ -31,8 +31,9 @@
 #include <errno.h>
 #include <stdlib.h>
 
+#include <async_safe/log.h>
+
 #include "local.h"
-#include "private/libc_logging.h"
 
 size_t __fbufsize(FILE* fp) {
   return fp->_bf._size;
@@ -83,7 +84,7 @@
 
   if (type != FSETLOCKING_INTERNAL && type != FSETLOCKING_BYCALLER) {
     // The API doesn't let us report an error, so blow up.
-    __libc_fatal("Bad type (%d) passed to __fsetlocking", type);
+    async_safe_fatal("Bad type (%d) passed to __fsetlocking", type);
   }
 
   _EXT(fp)->_caller_handles_locking = (type == FSETLOCKING_BYCALLER);
diff --git a/libc/upstream-openbsd/android/include/arc4random.h b/libc/upstream-openbsd/android/include/arc4random.h
index 0d70c81..d006045 100644
--- a/libc/upstream-openbsd/android/include/arc4random.h
+++ b/libc/upstream-openbsd/android/include/arc4random.h
@@ -27,8 +27,9 @@
 #include <pthread.h>
 #include <signal.h>
 
+#include <async_safe/log.h>
+
 #include "private/bionic_prctl.h"
-#include "private/libc_logging.h"
 
 // Android gets these from "thread_private.h".
 #include "thread_private.h"
@@ -47,7 +48,7 @@
 static inline void
 _getentropy_fail(void)
 {
-	__libc_fatal("getentropy failed");
+	async_safe_fatal("getentropy failed");
 }
 
 volatile sig_atomic_t _rs_forked;
diff --git a/libdl/libdl.arm.map b/libdl/libdl.arm.map
index c0dcd5d..668f008 100644
--- a/libdl/libdl.arm.map
+++ b/libdl/libdl.arm.map
@@ -47,4 +47,5 @@
     android_init_anonymous_namespace;
     android_create_namespace;
     android_link_namespaces;
+    android_get_exported_namespace;
 } LIBC_N;
diff --git a/libdl/libdl.arm64.map b/libdl/libdl.arm64.map
index 3b797f7..8270fe9 100644
--- a/libdl/libdl.arm64.map
+++ b/libdl/libdl.arm64.map
@@ -46,4 +46,5 @@
     android_init_anonymous_namespace;
     android_create_namespace;
     android_link_namespaces;
+    android_get_exported_namespace;
 } LIBC_N;
diff --git a/libdl/libdl.c b/libdl/libdl.c
index 6a95629..1a65b67 100644
--- a/libdl/libdl.c
+++ b/libdl/libdl.c
@@ -94,6 +94,9 @@
 __attribute__((__weak__, visibility("default")))
 void __loader_android_dlwarning(void* obj, void (*f)(void*, const char*));
 
+__attribute__((__weak__, visibility("default")))
+struct android_namespace_t* __loader_android_get_exported_namespace(const char* name);
+
 // Proxy calls to bionic loader
 void* dlopen(const char* filename, int flag) {
   const void* caller_addr = __builtin_return_address(0);
@@ -128,6 +131,11 @@
 }
 #endif
 
+/*
+ * This needs to be defined as weak because it is also defined in libc.a.
+ * Without this, static executables will have a multiple definition error.
+ */
+__attribute__((__weak__))
 int dl_iterate_phdr(int (*cb)(struct dl_phdr_info* info, size_t size, void* data), void* data) {
   return __loader_dl_iterate_phdr(cb, data);
 }
@@ -182,3 +190,7 @@
 void android_dlwarning(void* obj, void (*f)(void*, const char*)) {
   __loader_android_dlwarning(obj, f);
 }
+
+struct android_namespace_t* android_get_exported_namespace(const char* name) {
+  return __loader_android_get_exported_namespace(name);
+}
diff --git a/libdl/libdl.map.txt b/libdl/libdl.map.txt
index 245e016..a4c6483 100644
--- a/libdl/libdl.map.txt
+++ b/libdl/libdl.map.txt
@@ -46,4 +46,5 @@
     android_init_anonymous_namespace;
     android_create_namespace;
     android_link_namespaces;
+    android_get_exported_namespace;
 } LIBC_N;
diff --git a/libdl/libdl.mips.map b/libdl/libdl.mips.map
index 3b797f7..8270fe9 100644
--- a/libdl/libdl.mips.map
+++ b/libdl/libdl.mips.map
@@ -46,4 +46,5 @@
     android_init_anonymous_namespace;
     android_create_namespace;
     android_link_namespaces;
+    android_get_exported_namespace;
 } LIBC_N;
diff --git a/libdl/libdl.mips64.map b/libdl/libdl.mips64.map
index 3b797f7..8270fe9 100644
--- a/libdl/libdl.mips64.map
+++ b/libdl/libdl.mips64.map
@@ -46,4 +46,5 @@
     android_init_anonymous_namespace;
     android_create_namespace;
     android_link_namespaces;
+    android_get_exported_namespace;
 } LIBC_N;
diff --git a/libdl/libdl.x86.map b/libdl/libdl.x86.map
index 3b797f7..8270fe9 100644
--- a/libdl/libdl.x86.map
+++ b/libdl/libdl.x86.map
@@ -46,4 +46,5 @@
     android_init_anonymous_namespace;
     android_create_namespace;
     android_link_namespaces;
+    android_get_exported_namespace;
 } LIBC_N;
diff --git a/libdl/libdl.x86_64.map b/libdl/libdl.x86_64.map
index 3b797f7..8270fe9 100644
--- a/libdl/libdl.x86_64.map
+++ b/libdl/libdl.x86_64.map
@@ -46,4 +46,5 @@
     android_init_anonymous_namespace;
     android_create_namespace;
     android_link_namespaces;
+    android_get_exported_namespace;
 } LIBC_N;
diff --git a/linker/Android.bp b/linker/Android.bp
index d617189..efd91ac 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -9,6 +9,8 @@
 
     // We need to access Bionic private headers in the linker.
     include_dirs: ["bionic/libc"],
+
+    static_libs: ["libasync_safe"],
 }
 
 cc_binary {
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index 0bc5a31..6195d40 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -214,6 +214,10 @@
   return success;
 }
 
+android_namespace_t* __android_get_exported_namespace(const char* name) {
+  return get_exported_namespace(name);
+}
+
 void __cfi_fail(uint64_t CallSiteTypeId, void* Ptr, void *DiagData, void *CallerPc) {
   CFIShadowWriter::CfiFail(CallSiteTypeId, Ptr, DiagData, CallerPc);
 }
@@ -256,9 +260,13 @@
   // 4*
   // 0000000 000111111111122222222223333 333333444444444455 555555556666666666777777777788888 888889999999999
   // 0123456 789012345678901234567890123 456789012345678901 234567890123456789012345678901234 567890123456789
-    "dlvsym\0__loader_android_dlwarning\0__loader_cfi_fail\0__loader_android_link_namespaces\0"
+    "dlvsym\0__loader_android_dlwarning\0__loader_cfi_fail\0__loader_android_link_namespaces\0__loader_androi"
+  // 5*
+  // 0000000000111111111122222 22222
+  // 0123456789012345678901234 56789
+    "d_get_exported_namespace\0"
 #if defined(__arm__)
-  // 485
+  // 525
     "__loader_dl_unwind_find_exidx\0"
 #endif
     ;
@@ -286,8 +294,9 @@
   ELFW(SYM_INITIALIZER)(407, &__android_dlwarning, 1),
   ELFW(SYM_INITIALIZER)(434, &__cfi_fail, 1),
   ELFW(SYM_INITIALIZER)(452, &__android_link_namespaces, 1),
+  ELFW(SYM_INITIALIZER)(485, &__android_get_exported_namespace, 1),
 #if defined(__arm__)
-  ELFW(SYM_INITIALIZER)(485, &__dl_unwind_find_exidx, 1),
+  ELFW(SYM_INITIALIZER)(525, &__dl_unwind_find_exidx, 1),
 #endif
 };
 
@@ -304,9 +313,9 @@
 // Note that adding any new symbols here requires stubbing them out in libdl.
 static unsigned g_libdl_buckets[1] = { 1 };
 #if defined(__arm__)
-static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 0 };
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0 };
 #else
-static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 0 };
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 0 };
 #endif
 
 static uint8_t __libdl_info_buf[sizeof(soinfo)] __attribute__((aligned(8)));
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 39062e6..cd2c55b 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -36,6 +36,7 @@
 #include <string.h>
 #include <sys/mman.h>
 #include <sys/param.h>
+#include <sys/vfs.h>
 #include <unistd.h>
 
 #include <new>
@@ -45,6 +46,8 @@
 
 #include <android-base/scopeguard.h>
 
+#include <async_safe/log.h>
+
 // Private C library headers.
 
 #include "linker.h"
@@ -72,6 +75,7 @@
 #define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
 
 static android_namespace_t* g_anonymous_namespace = &g_default_namespace;
+static std::unordered_map<std::string, android_namespace_t*> g_exported_namespaces;
 
 static LinkerTypeAllocator<soinfo> g_soinfo_allocator;
 static LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
@@ -342,7 +346,7 @@
 
 static bool realpath_fd(int fd, std::string* realpath) {
   std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
-  __libc_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
+  async_safe_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
   if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
     PRINT("readlink(\"%s\") failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
     return false;
@@ -491,7 +495,7 @@
   }
 
   if (ref_count_ == 0) { // overflow
-    __libc_fatal("Too many nested calls to dlopen()");
+    async_safe_fatal("Too many nested calls to dlopen()");
   }
 }
 
@@ -990,7 +994,7 @@
 }
 
 static bool format_path(char* buf, size_t buf_size, const char* path, const char* name) {
-  int n = __libc_format_buffer(buf, buf_size, "%s/%s", path, name);
+  int n = async_safe_format_buffer(buf, buf_size, "%s/%s", path, name);
   if (n < 0 || n >= static_cast<int>(buf_size)) {
     PRINT("Warning: ignoring very long library path: %s/%s", path, name);
     return false;
@@ -1189,7 +1193,15 @@
     return false;
   }
 
-  if (!ns->is_accessible(realpath)) {
+  struct statfs fs_stat;
+  if (TEMP_FAILURE_RETRY(fstatfs(task->get_fd(), &fs_stat)) != 0) {
+    DL_ERR("unable to fstatfs file for the library \"%s\": %s", name, strerror(errno));
+    return false;
+  }
+
+  // do not check accessibility using realpath if fd is located on tmpfs
+  // this enables use of memfd_create() for apps
+  if ((fs_stat.f_type != TMPFS_MAGIC) && (!ns->is_accessible(realpath))) {
     // TODO(dimitry): workaround for http://b/26394120 - the grey-list
 
     // TODO(dimitry) before O release: add a namespace attribute to have this enabled
@@ -1771,7 +1783,7 @@
       }
     } else {
 #if !defined(__work_around_b_24465209__)
-      __libc_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
+      async_safe_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
 #else
       PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
       for_each_dt_needed(si, [&] (const char* library_name) {
@@ -1845,8 +1857,8 @@
   }
 
   if (buffer_size < required_size) {
-    __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
-                 "buffer len %zu, required len %zu", buffer_size, required_size);
+    async_safe_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
+                     "buffer len %zu, required len %zu", buffer_size, required_size);
   }
 
   char* end = buffer;
@@ -2172,18 +2184,36 @@
   android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
   ns->set_name(name);
   ns->set_isolated((type & ANDROID_NAMESPACE_TYPE_ISOLATED) != 0);
-  ns->set_ld_library_paths(std::move(ld_library_paths));
-  ns->set_default_library_paths(std::move(default_library_paths));
-  ns->set_permitted_paths(std::move(permitted_paths));
 
   if ((type & ANDROID_NAMESPACE_TYPE_SHARED) != 0) {
+    // append parent namespace paths.
+    std::copy(parent_namespace->get_ld_library_paths().begin(),
+              parent_namespace->get_ld_library_paths().end(),
+              back_inserter(ld_library_paths));
+
+    std::copy(parent_namespace->get_default_library_paths().begin(),
+              parent_namespace->get_default_library_paths().end(),
+              back_inserter(default_library_paths));
+
+    std::copy(parent_namespace->get_permitted_paths().begin(),
+              parent_namespace->get_permitted_paths().end(),
+              back_inserter(permitted_paths));
+
     // If shared - clone the parent namespace
     add_soinfos_to_namespace(parent_namespace->soinfo_list(), ns);
+    // and copy parent namespace links
+    for (auto& link : parent_namespace->linked_namespaces()) {
+      ns->add_linked_namespace(link.linked_namespace(), link.shared_lib_sonames());
+    }
   } else {
     // If not shared - copy only the shared group
     add_soinfos_to_namespace(get_shared_group(parent_namespace), ns);
   }
 
+  ns->set_ld_library_paths(std::move(ld_library_paths));
+  ns->set_default_library_paths(std::move(default_library_paths));
+  ns->set_permitted_paths(std::move(permitted_paths));
+
   return ns;
 }
 
@@ -3461,6 +3491,9 @@
     ns->set_permitted_paths(ns_config->permitted_paths());
 
     namespaces[ns_config->name()] = ns;
+    if (ns_config->visible()) {
+      g_exported_namespaces[ns_config->name()] = ns;
+    }
   }
 
   // 3. Establish links between namespaces
@@ -3485,3 +3518,16 @@
 
   set_application_target_sdk_version(config->target_sdk_version());
 }
+
+// This function finds a namespace exported in ld.config.txt by its name.
+// A namespace can be exported by setting .visible property to true.
+android_namespace_t* get_exported_namespace(const char* name) {
+  if (name == nullptr) {
+    return nullptr;
+  }
+  auto it = g_exported_namespaces.find(std::string(name));
+  if (it == g_exported_namespaces.end()) {
+    return nullptr;
+  }
+  return it->second;
+}
diff --git a/linker/linker.h b/linker/linker.h
index d5d4980..fdd7b66 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -38,7 +38,6 @@
 #include <unistd.h>
 
 #include "private/bionic_page.h"
-#include "private/libc_logging.h"
 #include "linked_list.h"
 #include "linker_common_types.h"
 #include "linker_logger.h"
@@ -173,4 +172,6 @@
                      android_namespace_t* namespace_to,
                      const char* shared_lib_sonames);
 
+android_namespace_t* get_exported_namespace(const char* name);
+
 #endif
diff --git a/linker/linker_allocator.cpp b/linker/linker_allocator.cpp
index 723ea2b..fd6f496 100644
--- a/linker/linker_allocator.cpp
+++ b/linker/linker_allocator.cpp
@@ -37,6 +37,8 @@
 #include <sys/mman.h>
 #include <unistd.h>
 
+#include <async_safe/log.h>
+
 #include "private/bionic_prctl.h"
 
 //
@@ -149,7 +151,7 @@
   ssize_t offset = reinterpret_cast<uintptr_t>(ptr) - sizeof(page_info);
 
   if (offset % block_size_ != 0) {
-    __libc_fatal("invalid pointer: %p (block_size=%zd)", ptr, block_size_);
+    async_safe_fatal("invalid pointer: %p (block_size=%zd)", ptr, block_size_);
   }
 
   memset(ptr, 0, block_size_);
@@ -180,7 +182,7 @@
 
   if (it == page_records_.end() || it->page_addr != addr) {
     // not found...
-    __libc_fatal("page record for %p was not found (block_size=%zd)", ptr, block_size_);
+    async_safe_fatal("page record for %p was not found (block_size=%zd)", ptr, block_size_);
   }
 
   return it;
@@ -203,7 +205,7 @@
   void* map_ptr = mmap(nullptr, PAGE_SIZE,
       PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
   if (map_ptr == MAP_FAILED) {
-    __libc_fatal("mmap failed");
+    async_safe_fatal("mmap failed");
   }
 
   prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, map_ptr, PAGE_SIZE, "linker_alloc_small_objects");
@@ -248,7 +250,7 @@
       PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
 
   if (map_ptr == MAP_FAILED) {
-    __libc_fatal("mmap failed");
+    async_safe_fatal("mmap failed");
   }
 
   prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, map_ptr, allocated_size, "linker_alloc_lob");
@@ -283,7 +285,7 @@
 page_info* LinkerMemoryAllocator::get_page_info(void* ptr) {
   page_info* info = reinterpret_cast<page_info*>(PAGE_START(reinterpret_cast<size_t>(ptr)));
   if (memcmp(info->signature, kSignature, sizeof(kSignature)) != 0) {
-    __libc_fatal("invalid pointer %p (page signature mismatch)", ptr);
+    async_safe_fatal("invalid pointer %p (page signature mismatch)", ptr);
   }
 
   return info;
@@ -308,7 +310,7 @@
   } else {
     LinkerSmallObjectAllocator* allocator = get_small_object_allocator(info->type);
     if (allocator != info->allocator_addr) {
-      __libc_fatal("invalid pointer %p (page signature mismatch)", ptr);
+      async_safe_fatal("invalid pointer %p (page signature mismatch)", ptr);
     }
 
     old_size = allocator->get_block_size();
@@ -336,7 +338,7 @@
   } else {
     LinkerSmallObjectAllocator* allocator = get_small_object_allocator(info->type);
     if (allocator != info->allocator_addr) {
-      __libc_fatal("invalid pointer %p (invalid allocator address for the page)", ptr);
+      async_safe_fatal("invalid pointer %p (invalid allocator address for the page)", ptr);
     }
 
     allocator->free(ptr);
@@ -345,7 +347,7 @@
 
 LinkerSmallObjectAllocator* LinkerMemoryAllocator::get_small_object_allocator(uint32_t type) {
   if (type < kSmallObjectMinSizeLog2 || type > kSmallObjectMaxSizeLog2) {
-    __libc_fatal("invalid type: %u", type);
+    async_safe_fatal("invalid type: %u", type);
   }
 
   initialize_allocators();
diff --git a/linker/linker_allocator.h b/linker/linker_allocator.h
index beffc52..80ae508 100644
--- a/linker/linker_allocator.h
+++ b/linker/linker_allocator.h
@@ -37,8 +37,9 @@
 
 #include <vector>
 
+#include <async_safe/log.h>
+
 #include "private/bionic_prctl.h"
-#include "private/libc_logging.h"
 
 const uint32_t kSmallObjectMaxSizeLog2 = 10;
 const uint32_t kSmallObjectMinSizeLog2 = 4;
@@ -92,7 +93,7 @@
     if (ptr == MAP_FAILED) {
       // Spec says we need to throw std::bad_alloc here but because our
       // code does not support exception handling anyways - we are going to abort.
-      __libc_fatal("mmap failed");
+      async_safe_fatal("mmap failed");
     }
 
     prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, size, "linker_alloc_vector");
diff --git a/linker/linker_config.cpp b/linker/linker_config.cpp
index a12cfbe..0a9aeab 100644
--- a/linker/linker_config.cpp
+++ b/linker/linker_config.cpp
@@ -36,6 +36,8 @@
 #include <android-base/scopeguard.h>
 #include <android-base/strings.h>
 
+#include <async_safe/log.h>
+
 #include <stdlib.h>
 
 #include <string>
@@ -149,7 +151,7 @@
                                     size_t lineno,
                                     const std::string& msg) {
   char buf[1024];
-  __libc_format_buffer(buf, sizeof(buf), "%s:%zu: error: %s", file, lineno, msg.c_str());
+  async_safe_format_buffer(buf, sizeof(buf), "%s:%zu: error: %s", file, lineno, msg.c_str());
 
   return std::string(buf);
 }
@@ -328,7 +330,7 @@
     params.push_back({ "LIB", kLibParamValue });
     if (target_sdk_version_ != 0) {
       char buf[16];
-      __libc_format_buffer(buf, sizeof(buf), "%d", target_sdk_version_);
+      async_safe_format_buffer(buf, sizeof(buf), "%d", target_sdk_version_);
       params.push_back({ "SDK_VER", buf });
     }
 
@@ -456,6 +458,7 @@
     }
 
     ns_config->set_isolated(properties.get_bool(property_name_prefix + ".isolated"));
+    ns_config->set_visible(properties.get_bool(property_name_prefix + ".visible"));
 
     // these are affected by is_asan flag
     if (is_asan) {
diff --git a/linker/linker_config.h b/linker/linker_config.h
index 4ec8b26..6f8bffb 100644
--- a/linker/linker_config.h
+++ b/linker/linker_config.h
@@ -62,7 +62,7 @@
 class NamespaceConfig {
  public:
   explicit NamespaceConfig(const std::string& name)
-      : name_(name), isolated_(false)
+      : name_(name), isolated_(false), visible_(false)
   {}
 
   const char* name() const {
@@ -73,6 +73,10 @@
     return isolated_;
   }
 
+  bool visible() const {
+    return visible_;
+  }
+
   const std::vector<std::string>& search_paths() const {
     return search_paths_;
   }
@@ -93,6 +97,10 @@
     isolated_ = isolated;
   }
 
+  void set_visible(bool visible) {
+    visible_ = visible;
+  }
+
   void set_search_paths(std::vector<std::string>&& search_paths) {
     search_paths_ = search_paths;
   }
@@ -103,6 +111,7 @@
  private:
   const std::string name_;
   bool isolated_;
+  bool visible_;
   std::vector<std::string> search_paths_;
   std::vector<std::string> permitted_paths_;
   std::vector<NamespaceLinkConfig> namespace_links_;
diff --git a/linker/linker_debug.h b/linker/linker_debug.h
index 42796e9..7ceab08 100644
--- a/linker/linker_debug.h
+++ b/linker/linker_debug.h
@@ -54,20 +54,21 @@
  * To enable/disable specific debug options, change the defines above
  *********************************************************************/
 
-#include "private/libc_logging.h"
 #include <unistd.h>
 
+#include <async_safe/log.h>
+
 __LIBC_HIDDEN__ extern int g_ld_debug_verbosity;
 
 #if LINKER_DEBUG_TO_LOG
 #define _PRINTVF(v, x...) \
     do { \
-      if (g_ld_debug_verbosity > (v)) __libc_format_log(5-(v), "linker", x); \
+      if (g_ld_debug_verbosity > (v)) async_safe_format_log(5-(v), "linker", x); \
     } while (0)
 #else /* !LINKER_DEBUG_TO_LOG */
 #define _PRINTVF(v, x...) \
     do { \
-      if (g_ld_debug_verbosity > (v)) { __libc_format_fd(1, x); write(1, "\n", 1); } \
+      if (g_ld_debug_verbosity > (v)) { async_safe_format_fd(1, x); write(1, "\n", 1); } \
     } while (0)
 #endif /* !LINKER_DEBUG_TO_LOG */
 
diff --git a/linker/linker_globals.h b/linker/linker_globals.h
index 1ed479c..d8134af 100644
--- a/linker/linker_globals.h
+++ b/linker/linker_globals.h
@@ -34,20 +34,20 @@
 
 #include <unordered_map>
 
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
 
 #define DL_ERR(fmt, x...) \
     do { \
-      __libc_format_buffer(linker_get_error_buffer(), linker_get_error_buffer_size(), fmt, ##x); \
+      async_safe_format_buffer(linker_get_error_buffer(), linker_get_error_buffer_size(), fmt, ##x); \
       /* If LD_DEBUG is set high enough, log every dlerror(3) message. */ \
     } while (false)
 
 #define DL_WARN(fmt, x...) \
     do { \
-      __libc_format_log(ANDROID_LOG_WARN, "linker", fmt, ##x); \
-      __libc_format_fd(2, "WARNING: linker: "); \
-      __libc_format_fd(2, fmt, ##x); \
-      __libc_format_fd(2, "\n"); \
+      async_safe_format_log(ANDROID_LOG_WARN, "linker", fmt, ##x); \
+      async_safe_format_fd(2, "WARNING: linker: "); \
+      async_safe_format_fd(2, fmt, ##x); \
+      async_safe_format_fd(2, "\n"); \
     } while (false)
 
 #define DL_ERR_AND_LOG(fmt, x...) \
diff --git a/linker/linker_libcxx_support.cpp b/linker/linker_libcxx_support.cpp
index e7b23e0..11e0f40 100644
--- a/linker/linker_libcxx_support.cpp
+++ b/linker/linker_libcxx_support.cpp
@@ -26,8 +26,8 @@
  * SUCH DAMAGE.
  */
 
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
 
 void* __find_icu_symbol(const char* symbol_name __attribute__((__unused__))) {
-  __libc_fatal("__find_icu_symbol should not be called in the linker");
+  async_safe_fatal("__find_icu_symbol should not be called in the linker");
 }
diff --git a/linker/linker_logger.cpp b/linker/linker_logger.cpp
index 717667c..4c6603b 100644
--- a/linker/linker_logger.cpp
+++ b/linker/linker_logger.cpp
@@ -35,9 +35,10 @@
 #include <string>
 #include <vector>
 
+#include <async_safe/log.h>
+
 #include "android-base/strings.h"
 #include "private/CachedProperty.h"
-#include "private/libc_logging.h"
 
 LinkerLogger g_linker_logger;
 bool g_greylist_disabled = false;
@@ -59,8 +60,8 @@
     } else if (o == "dlsym") {
       flags |= kLogDlsym;
     } else {
-      __libc_format_log(ANDROID_LOG_WARN, "linker", "Ignoring unknown debug.ld option \"%s\"",
-                        o.c_str());
+      async_safe_format_log(ANDROID_LOG_WARN, "linker", "Ignoring unknown debug.ld option \"%s\"",
+                            o.c_str());
     }
   }
 
@@ -95,8 +96,8 @@
   bool old_value = g_greylist_disabled;
   g_greylist_disabled = (strcmp(greylist_disabled.Get(), "true") == 0);
   if (g_greylist_disabled != old_value) {
-    __libc_format_log(ANDROID_LOG_INFO, "linker", "%s greylist",
-                      g_greylist_disabled ? "Disabling" : "Enabling");
+    async_safe_format_log(ANDROID_LOG_INFO, "linker", "%s greylist",
+                          g_greylist_disabled ? "Disabling" : "Enabling");
   }
 
   flags_ = 0;
@@ -124,6 +125,6 @@
 
   va_list ap;
   va_start(ap, format);
-  __libc_format_log_va_list(ANDROID_LOG_DEBUG, "linker", format, ap);
+  async_safe_format_log_va_list(ANDROID_LOG_DEBUG, "linker", format, ap);
   va_end(ap);
 }
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index 40f82a1..3d26e91 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -45,6 +45,8 @@
 #include "debuggerd/handler.h"
 #endif
 
+#include <async_safe/log.h>
+
 #include <vector>
 
 extern void __libc_init_globals(KernelArgumentBlock&);
@@ -189,7 +191,7 @@
     char path[PATH_MAX];
     ssize_t path_len = readlink("/proc/self/exe", path, sizeof(path));
     if (path_len == -1 || path_len >= static_cast<ssize_t>(sizeof(path))) {
-      __libc_fatal("readlink('/proc/self/exe') failed: %s", strerror(errno));
+      async_safe_fatal("readlink('/proc/self/exe') failed: %s", strerror(errno));
     }
     executable_path = std::string(path, path_len);
   }
@@ -267,13 +269,13 @@
   // the executable could be unlinked by this point and it should
   // not cause a crash (see http://b/31084669)
   if (TEMP_FAILURE_RETRY(stat("/proc/self/exe", &file_stat)) != 0) {
-    __libc_fatal("unable to stat \"/proc/self/exe\": %s", strerror(errno));
+    async_safe_fatal("unable to stat \"/proc/self/exe\": %s", strerror(errno));
   }
 
   const char* executable_path = get_executable_path();
   soinfo* si = soinfo_alloc(&g_default_namespace, executable_path, &file_stat, 0, RTLD_GLOBAL);
   if (si == nullptr) {
-    __libc_fatal("Couldn't allocate soinfo: out of memory?");
+    async_safe_fatal("Couldn't allocate soinfo: out of memory?");
   }
 
   /* bootstrap the link map, the main exe always needs to be first */
@@ -319,7 +321,7 @@
     // tombstone for them. The tombstone never provided any detail relevant to
     // fixing the problem anyway, and the utility of drawing extra attention
     // to the problem is non-existent at this late date.
-    __libc_format_fd(STDERR_FILENO,
+    async_safe_format_fd(STDERR_FILENO,
                      "\"%s\": error: Android 5.0 and later only support "
                      "position-independent executables (-fPIE).\n",
                      g_argv[0]);
@@ -335,7 +337,7 @@
   init_default_namespace(executable_path);
 
   if (!si->prelink_image()) {
-    __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
+    async_safe_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
   }
 
   // add somain to global group
@@ -369,10 +371,10 @@
                       nullptr,
                       true /* add_as_children */,
                       true /* search_linked_namespaces */)) {
-    __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
+    async_safe_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
   } else if (needed_libraries_count == 0) {
     if (!si->link_image(g_empty_list, soinfo_list_t::make_list(si), nullptr)) {
-      __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
+      async_safe_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
     }
     si->increment_ref_count();
   }
@@ -380,7 +382,7 @@
   add_vdso(args);
 
   if (!get_cfi_shadow()->InitialLinkDone(solist)) {
-    __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
+    async_safe_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
   }
 
   si->call_pre_init_constructors();
@@ -464,7 +466,7 @@
 }
 
 static void __linker_cannot_link(const char* argv0) {
-  __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", argv0, linker_get_error_buffer());
+  async_safe_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", argv0, linker_get_error_buffer());
 }
 
 /*
@@ -546,7 +548,7 @@
   // This happens when user tries to run 'adb shell /system/bin/linker'
   // see also https://code.google.com/p/android/issues/detail?id=63174
   if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) {
-    __libc_format_fd(STDOUT_FILENO,
+    async_safe_format_fd(STDOUT_FILENO,
                      "This is %s, the helper program for dynamic executables.\n",
                      args.argv[0]);
     exit(0);
diff --git a/linker/linker_memory.cpp b/linker/linker_memory.cpp
index f8852e1..472c4e8 100644
--- a/linker/linker_memory.cpp
+++ b/linker/linker_memory.cpp
@@ -32,7 +32,7 @@
 #include <sys/cdefs.h>
 #include <unistd.h>
 
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
 
 static LinkerMemoryAllocator g_linker_allocator;
 static pid_t fallback_tid = 0;
@@ -41,7 +41,7 @@
 // case the linker heap is corrupted. Do not use this function.
 extern "C" void __linker_enable_fallback_allocator() {
   if (fallback_tid != 0) {
-    __libc_fatal("attempted to use currently-in-use fallback allocator");
+    async_safe_fatal("attempted to use currently-in-use fallback allocator");
   }
 
   fallback_tid = gettid();
@@ -49,7 +49,7 @@
 
 extern "C" void __linker_disable_fallback_allocator() {
   if (fallback_tid == 0) {
-    __libc_fatal("attempted to disable unused fallback allocator");
+    async_safe_fatal("attempted to disable unused fallback allocator");
   }
 
   fallback_tid = 0;
diff --git a/linker/linker_namespaces.h b/linker/linker_namespaces.h
index e7d9b2e..c3260fd 100644
--- a/linker/linker_namespaces.h
+++ b/linker/linker_namespaces.h
@@ -48,6 +48,10 @@
     return linked_namespace_;
   }
 
+  const std::unordered_set<std::string>& shared_lib_sonames() const {
+    return shared_lib_sonames_;
+  }
+
   bool is_accessible(const char* soname) const {
     return shared_lib_sonames_.find(soname) != shared_lib_sonames_.end();
   }
diff --git a/linker/linker_sleb128.h b/linker/linker_sleb128.h
index 74b69e4..01e127d 100644
--- a/linker/linker_sleb128.h
+++ b/linker/linker_sleb128.h
@@ -31,6 +31,8 @@
 
 #include <stdint.h>
 
+#include <async_safe/log.h>
+
 #include "linker_debug.h"
 
 // Helper classes for decoding LEB128, used in packed relocation data.
@@ -50,7 +52,7 @@
 
     do {
       if (current_ >= end_) {
-        __libc_fatal("sleb128_decoder ran out of bounds");
+        async_safe_fatal("sleb128_decoder ran out of bounds");
       }
       byte = *current_++;
       value |= (static_cast<size_t>(byte & 127) << shift);
diff --git a/linker/linker_soinfo.cpp b/linker/linker_soinfo.cpp
index 1d59dbb..fbff7cf 100644
--- a/linker/linker_soinfo.cpp
+++ b/linker/linker_soinfo.cpp
@@ -34,6 +34,8 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
+#include <async_safe/log.h>
+
 #include "linker_debug.h"
 #include "linker_globals.h"
 #include "linker_logger.h"
@@ -636,7 +638,7 @@
 
 const char* soinfo::get_string(ElfW(Word) index) const {
   if (has_min_version(1) && (index >= strtab_size_)) {
-    __libc_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d",
+    async_safe_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d",
         get_realpath(), strtab_size_, index);
   }
 
diff --git a/linker/tests/Android.mk b/linker/tests/Android.mk
index 61c43c9..8284bea 100644
--- a/linker/tests/Android.mk
+++ b/linker/tests/Android.mk
@@ -51,9 +51,6 @@
   ../linker_config.cpp \
   ../linker_utils.cpp \
 
-# for __libc_fatal
-LOCAL_SRC_FILES += ../../libc/bionic/libc_logging.cpp
-
-LOCAL_STATIC_LIBRARIES += libbase
+LOCAL_STATIC_LIBRARIES += libasync_safe libbase
 
 include $(BUILD_NATIVE_TEST)
diff --git a/linker/tests/linker_config_test.cpp b/linker/tests/linker_config_test.cpp
index 418cbda..5e51113 100644
--- a/linker/tests/linker_config_test.cpp
+++ b/linker/tests/linker_config_test.cpp
@@ -58,6 +58,7 @@
   "namespace.default.links = system\n"
   "namespace.default.link.system.shared_libs = libc.so:libm.so:libdl.so:libstdc++.so\n"
   "namespace.system.isolated = true\n"
+  "namespace.system.visible = true\n"
   "namespace.system.search.paths = /system/${LIB}\n"
   "namespace.system.permitted.paths = /system/${LIB}\n"
   "namespace.system.asan.search.paths = /data:/system/${LIB}\n"
@@ -137,6 +138,7 @@
   ASSERT_TRUE(default_ns_config != nullptr);
 
   ASSERT_TRUE(default_ns_config->isolated());
+  ASSERT_FALSE(default_ns_config->visible());
   ASSERT_EQ(kExpectedDefaultSearchPath, default_ns_config->search_paths());
   ASSERT_EQ(kExpectedDefaultPermittedPath, default_ns_config->permitted_paths());
 
@@ -163,6 +165,7 @@
   ASSERT_TRUE(ns_system != nullptr) << "system namespace was not found";
 
   ASSERT_TRUE(ns_system->isolated());
+  ASSERT_TRUE(ns_system->visible());
   ASSERT_EQ(kExpectedSystemSearchPath, ns_system->search_paths());
   ASSERT_EQ(kExpectedSystemPermittedPath, ns_system->permitted_paths());
 }
diff --git a/tests/Android.bp b/tests/Android.bp
index ae8d7fc..4605267 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -52,12 +52,14 @@
     defaults: ["bionic_tests_defaults"],
     srcs: [
         "arpa_inet_test.cpp",
+        "async_safe_test.cpp",
         "assert_test.cpp",
         "buffer_tests.cpp",
         "bug_26110743_test.cpp",
         "complex_test.cpp",
         "ctype_test.cpp",
         "dirent_test.cpp",
+        "elf_test.cpp",
         "endian_test.cpp",
         "error_test.cpp",
         "eventfd_test.cpp",
@@ -71,9 +73,9 @@
         "inttypes_test.cpp",
         "langinfo_test.cpp",
         "leak_test.cpp",
-        "libc_logging_test.cpp",
         "libgen_basename_test.cpp",
         "libgen_test.cpp",
+        "linux_swab_test.cpp",
         "locale_test.cpp",
         "malloc_test.cpp",
         "math_test.cpp",
@@ -149,6 +151,12 @@
         "external/tinyxml2",
     ],
 
+    target: {
+        android: {
+            whole_static_libs: ["libasync_safe"],
+        },
+    },
+
     static_libs: [
         "libtinyxml2",
         "liblog",
@@ -256,6 +264,7 @@
         "dl_test.cpp",
         "dlfcn_symlink_support.cpp",
         "dlfcn_test.cpp",
+        "link_test.cpp",
         "pthread_dlfcn_test.cpp",
     ],
     static_libs: [
diff --git a/tests/async_safe_test.cpp b/tests/async_safe_test.cpp
new file mode 100644
index 0000000..3d6fcaa
--- /dev/null
+++ b/tests/async_safe_test.cpp
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#if defined(__BIONIC__)
+#include <async_safe/log.h>
+#endif // __BIONIC__
+
+TEST(async_safe_log, smoke) {
+#if defined(__BIONIC__)
+  char buf[BUFSIZ];
+
+  async_safe_format_buffer(buf, sizeof(buf), "a");
+  EXPECT_STREQ("a", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "%%");
+  EXPECT_STREQ("%", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "01234");
+  EXPECT_STREQ("01234", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%sb", "01234");
+  EXPECT_STREQ("a01234b", buf);
+
+  char* s = NULL;
+  async_safe_format_buffer(buf, sizeof(buf), "a%sb", s);
+  EXPECT_STREQ("a(null)b", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "aa%scc", "bb");
+  EXPECT_STREQ("aabbcc", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%cc", 'b');
+  EXPECT_STREQ("abc", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%db", 1234);
+  EXPECT_STREQ("a1234b", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%db", -8123);
+  EXPECT_STREQ("a-8123b", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%hdb", static_cast<short>(0x7fff0010));
+  EXPECT_STREQ("a16b", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%hhdb", static_cast<char>(0x7fffff10));
+  EXPECT_STREQ("a16b", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%lldb", 0x1000000000LL);
+  EXPECT_STREQ("a68719476736b", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%ldb", 70000L);
+  EXPECT_STREQ("a70000b", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%pb", reinterpret_cast<void*>(0xb0001234));
+  EXPECT_STREQ("a0xb0001234b", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%xz", 0x12ab);
+  EXPECT_STREQ("a12abz", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%Xz", 0x12ab);
+  EXPECT_STREQ("a12ABz", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%08xz", 0x123456);
+  EXPECT_STREQ("a00123456z", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%5dz", 1234);
+  EXPECT_STREQ("a 1234z", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%05dz", 1234);
+  EXPECT_STREQ("a01234z", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%8dz", 1234);
+  EXPECT_STREQ("a    1234z", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%-8dz", 1234);
+  EXPECT_STREQ("a1234    z", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "A%-11sZ", "abcdef");
+  EXPECT_STREQ("Aabcdef     Z", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "A%s:%dZ", "hello", 1234);
+  EXPECT_STREQ("Ahello:1234Z", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%03d:%d:%02dz", 5, 5, 5);
+  EXPECT_STREQ("a005:5:05z", buf);
+
+  void* p = NULL;
+  async_safe_format_buffer(buf, sizeof(buf), "a%d,%pz", 5, p);
+  EXPECT_STREQ("a5,0x0z", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%lld,%d,%d,%dz", 0x1000000000LL, 6, 7, 8);
+  EXPECT_STREQ("a68719476736,6,7,8z", buf);
+#else // __BIONIC__
+  GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif // __BIONIC__
+}
+
+TEST(async_safe_log, d_INT_MAX) {
+#if defined(__BIONIC__)
+  char buf[BUFSIZ];
+  async_safe_format_buffer(buf, sizeof(buf), "%d", INT_MAX);
+  EXPECT_STREQ("2147483647", buf);
+#else // __BIONIC__
+  GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif // __BIONIC__
+}
+
+TEST(async_safe_log, d_INT_MIN) {
+#if defined(__BIONIC__)
+  char buf[BUFSIZ];
+  async_safe_format_buffer(buf, sizeof(buf), "%d", INT_MIN);
+  EXPECT_STREQ("-2147483648", buf);
+#else // __BIONIC__
+  GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif // __BIONIC__
+}
+
+TEST(async_safe_log, ld_LONG_MAX) {
+#if defined(__BIONIC__)
+  char buf[BUFSIZ];
+  async_safe_format_buffer(buf, sizeof(buf), "%ld", LONG_MAX);
+#if defined(__LP64__)
+  EXPECT_STREQ("9223372036854775807", buf);
+#else
+  EXPECT_STREQ("2147483647", buf);
+#endif
+#else // __BIONIC__
+  GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif // __BIONIC__
+}
+
+TEST(async_safe_log, ld_LONG_MIN) {
+#if defined(__BIONIC__)
+  char buf[BUFSIZ];
+  async_safe_format_buffer(buf, sizeof(buf), "%ld", LONG_MIN);
+#if defined(__LP64__)
+  EXPECT_STREQ("-9223372036854775808", buf);
+#else
+  EXPECT_STREQ("-2147483648", buf);
+#endif
+#else // __BIONIC__
+  GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif // __BIONIC__
+}
+
+TEST(async_safe_log, lld_LLONG_MAX) {
+#if defined(__BIONIC__)
+  char buf[BUFSIZ];
+  async_safe_format_buffer(buf, sizeof(buf), "%lld", LLONG_MAX);
+  EXPECT_STREQ("9223372036854775807", buf);
+#else // __BIONIC__
+  GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif // __BIONIC__
+}
+
+TEST(async_safe_log, lld_LLONG_MIN) {
+#if defined(__BIONIC__)
+  char buf[BUFSIZ];
+  async_safe_format_buffer(buf, sizeof(buf), "%lld", LLONG_MIN);
+  EXPECT_STREQ("-9223372036854775808", buf);
+#else // __BIONIC__
+  GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif // __BIONIC__
+}
+
+TEST(async_safe_log, buffer_overrun) {
+#if defined(__BIONIC__)
+  char buf[BUFSIZ];
+  ASSERT_EQ(11, async_safe_format_buffer(buf, sizeof(buf), "hello %s", "world"));
+  EXPECT_STREQ("hello world", buf);
+  ASSERT_EQ(11, async_safe_format_buffer(buf, 8, "hello %s", "world"));
+  EXPECT_STREQ("hello w", buf);
+#else // __BIONIC__
+  GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif // __BIONIC__
+}
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index a0226a6..cf642cd 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -24,9 +24,14 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+
 #include <android/dlext.h>
+#include <android-base/strings.h>
+
+#include <linux/memfd.h>
 #include <sys/mman.h>
 #include <sys/types.h>
+#include <sys/vfs.h>
 #include <sys/wait.h>
 
 #include <pagemap/pagemap.h>
@@ -460,7 +465,8 @@
     EXPECT_EQ(1729U, *taxicab_number);
   }
 
-  void SpawnChildrenAndMeasurePss(const char* lib, bool share_relro, size_t* pss_out);
+  void SpawnChildrenAndMeasurePss(const char* lib, const char* relro_file, bool share_relro,
+                                  size_t* pss_out);
 
   android_dlextinfo extinfo_;
 };
@@ -506,19 +512,23 @@
   ASSERT_NOERROR(pipe(pipefd));
 
   size_t without_sharing, with_sharing;
-  ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(kLibName, false, &without_sharing));
-  ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(kLibName, true, &with_sharing));
+  ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(kLibName, tf.filename, false, &without_sharing));
+  ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(kLibName, tf.filename, true, &with_sharing));
+  ASSERT_LT(with_sharing, without_sharing);
 
-  // We expect the sharing to save at least 10% of the total PSS. In practice
-  // it saves 40%+ for this test.
-  size_t expected_size = without_sharing - (without_sharing/10);
-  EXPECT_LT(with_sharing, expected_size);
+  // We expect the sharing to save at least 50% of the library's total PSS.
+  // In practice it saves 80%+ for this library in the test.
+  size_t pss_saved = without_sharing - with_sharing;
+  size_t expected_min_saved = without_sharing / 2;
+
+  EXPECT_LT(expected_min_saved, pss_saved);
 
   // Use destructor of tf to close and unlink the file.
   tf.fd = extinfo_.relro_fd;
 }
 
-void getPss(pid_t pid, size_t* pss_out) {
+void GetPss(bool shared_relro, const char* lib, const char* relro_file, pid_t pid,
+            size_t* total_pss) {
   pm_kernel_t* kernel;
   ASSERT_EQ(0, pm_kernel_create(&kernel));
 
@@ -529,21 +539,28 @@
   size_t num_maps;
   ASSERT_EQ(0, pm_process_maps(process, &maps, &num_maps));
 
-  size_t total_pss = 0;
-  for (size_t i = 0; i < num_maps; i++) {
-    pm_memusage_t usage;
-    ASSERT_EQ(0, pm_map_usage(maps[i], &usage));
-    total_pss += usage.pss;
+  // Calculate total PSS of the library.
+  *total_pss = 0;
+  bool saw_relro_file = false;
+  for (size_t i = 0; i < num_maps; ++i) {
+    if (android::base::EndsWith(maps[i]->name, lib) || strcmp(maps[i]->name, relro_file) == 0) {
+      if (strcmp(maps[i]->name, relro_file) == 0) saw_relro_file = true;
+
+      pm_memusage_t usage;
+      ASSERT_EQ(0, pm_map_usage(maps[i], &usage));
+      *total_pss += usage.pss;
+    }
   }
-  *pss_out = total_pss;
 
   free(maps);
   pm_process_destroy(process);
   pm_kernel_destroy(kernel);
+
+  if (shared_relro) ASSERT_TRUE(saw_relro_file);
 }
 
-void DlExtRelroSharingTest::SpawnChildrenAndMeasurePss(const char* lib, bool share_relro,
-                                                       size_t* pss_out) {
+void DlExtRelroSharingTest::SpawnChildrenAndMeasurePss(const char* lib, const char* relro_file,
+                                                       bool share_relro, size_t* pss_out) {
   const int CHILDREN = 20;
 
   // Create children
@@ -596,11 +613,11 @@
     childpipe[i] = parent_done_pipe[1];
   }
 
-  // Sum the PSS of all the children
+  // Sum the PSS of tested library of all the children
   size_t total_pss = 0;
   for (int i=0; i<CHILDREN; ++i) {
     size_t child_pss;
-    ASSERT_NO_FATAL_FAILURE(getPss(child_pids[i], &child_pss));
+    ASSERT_NO_FATAL_FAILURE(GetPss(share_relro, lib, relro_file, child_pids[i], &child_pss));
     total_pss += child_pss;
   }
   *pss_out = total_pss;
@@ -802,6 +819,98 @@
   dlclose(handle2);
 }
 
+TEST(dlext, dlopen_ext_use_o_tmpfile_fd) {
+  const std::string lib_path = get_testlib_root() + "/libtest_simple.so";
+
+  int tmpfd = TEMP_FAILURE_RETRY(
+        open(get_testlib_root().c_str(), O_TMPFILE | O_CLOEXEC | O_RDWR | O_EXCL));
+
+  // Ignore kernels without O_TMPFILE flag support
+  if (tmpfd == -1 && (errno == EISDIR || errno == EINVAL || errno == EOPNOTSUPP)) {
+    return;
+  }
+
+  ASSERT_TRUE(tmpfd != -1) << strerror(errno);
+
+  android_namespace_t* ns =
+          android_create_namespace("testing-o_tmpfile",
+                                   nullptr,
+                                   get_testlib_root().c_str(),
+                                   ANDROID_NAMESPACE_TYPE_ISOLATED,
+                                   nullptr,
+                                   nullptr);
+
+  ASSERT_DL_NOTNULL(ns);
+
+  ASSERT_TRUE(android_link_namespaces(ns, nullptr, g_core_shared_libs.c_str())) << dlerror();
+
+  std::string content;
+  ASSERT_TRUE(android::base::ReadFileToString(lib_path, &content)) << strerror(errno);
+  ASSERT_TRUE(android::base::WriteStringToFd(content, tmpfd)) << strerror(errno);
+
+  android_dlextinfo extinfo;
+  extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_NAMESPACE;
+  extinfo.library_fd = tmpfd;
+  extinfo.library_namespace = ns;
+
+  void* handle = android_dlopen_ext("foobar", RTLD_NOW, &extinfo);
+
+  ASSERT_DL_NOTNULL(handle);
+
+  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number"));
+  ASSERT_DL_NOTNULL(taxicab_number);
+  EXPECT_EQ(1729U, *taxicab_number);
+  dlclose(handle);
+}
+
+TEST(dlext, dlopen_ext_use_memfd) {
+  const std::string lib_path = get_testlib_root() + "/libtest_simple.so";
+
+  // create memfd
+  int memfd = syscall(__NR_memfd_create, "foobar", MFD_CLOEXEC);
+  if (memfd == -1 && errno == ENOSYS) {
+    return;
+  }
+
+  ASSERT_TRUE(memfd != -1) << strerror(errno);
+
+  // Check st.f_type is TMPFS_MAGIC for memfd
+  struct statfs st;
+  ASSERT_TRUE(TEMP_FAILURE_RETRY(fstatfs(memfd, &st)) == 0) << strerror(errno);
+  ASSERT_EQ(static_cast<decltype(st.f_type)>(TMPFS_MAGIC), st.f_type);
+
+  android_namespace_t* ns =
+          android_create_namespace("testing-memfd",
+                                   nullptr,
+                                   get_testlib_root().c_str(),
+                                   ANDROID_NAMESPACE_TYPE_ISOLATED,
+                                   nullptr,
+                                   nullptr);
+
+  ASSERT_DL_NOTNULL(ns);
+
+  ASSERT_TRUE(android_link_namespaces(ns, nullptr, g_core_shared_libs.c_str())) << dlerror();
+
+  // read file into memfd backed one.
+  std::string content;
+  ASSERT_TRUE(android::base::ReadFileToString(lib_path, &content)) << strerror(errno);
+  ASSERT_TRUE(android::base::WriteStringToFd(content, memfd)) << strerror(errno);
+
+  android_dlextinfo extinfo;
+  extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_NAMESPACE;
+  extinfo.library_fd = memfd;
+  extinfo.library_namespace = ns;
+
+  void* handle = android_dlopen_ext("foobar", RTLD_NOW, &extinfo);
+
+  ASSERT_DL_NOTNULL(handle);
+
+  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number"));
+  ASSERT_DL_NOTNULL(taxicab_number);
+  EXPECT_EQ(1729U, *taxicab_number);
+  dlclose(handle);
+}
+
 TEST(dlext, ns_symbol_visibilty_one_namespace) {
   static const char* root_lib = "libnstest_root.so";
   ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
@@ -1254,6 +1363,70 @@
   dlclose(handle2);
 }
 
+TEST(dlext, ns_shared_links_and_paths) {
+  // Create parent namespace (isolated, not shared)
+  android_namespace_t* ns_isolated =
+          android_create_namespace("private_isolated",
+                                   nullptr,
+                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
+                                   ANDROID_NAMESPACE_TYPE_ISOLATED,
+                                   (get_testlib_root() + "/public_namespace_libs").c_str(),
+                                   nullptr);
+  ASSERT_TRUE(ns_isolated != nullptr) << dlerror();
+  ASSERT_TRUE(android_link_namespaces(ns_isolated, nullptr, g_core_shared_libs.c_str())) << dlerror();
+
+  // Create shared namespace with ns_isolated parent
+  android_namespace_t* ns_shared =
+          android_create_namespace("private_shared",
+                                   nullptr,
+                                   nullptr,
+                                   ANDROID_NAMESPACE_TYPE_SHARED | ANDROID_NAMESPACE_TYPE_ISOLATED,
+                                   nullptr,
+                                   ns_isolated);
+  ASSERT_TRUE(ns_shared != nullptr) << dlerror();
+
+  // 1. Load a library in ns_shared to check that it has inherited
+  // search path and the link to the default namespace.
+  android_dlextinfo extinfo;
+  extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+  extinfo.library_namespace = ns_shared;
+
+  {
+    void* handle = android_dlopen_ext("libnstest_private.so", RTLD_NOW, &extinfo);
+    ASSERT_TRUE(handle != nullptr) << dlerror();
+    const char** ns_private_extern_string = static_cast<const char**>(dlsym(handle, "g_private_extern_string"));
+    ASSERT_TRUE(ns_private_extern_string != nullptr) << dlerror();
+    ASSERT_STREQ("This string is from private namespace", *ns_private_extern_string);
+
+    dlclose(handle);
+  }
+  // 2. Load another test library by absolute path to check that
+  // it has inherited permitted_when_isolated_path
+  {
+    void* handle = android_dlopen_ext(
+            (get_testlib_root() + "/public_namespace_libs/libnstest_public.so").c_str(),
+            RTLD_NOW,
+            &extinfo);
+
+    ASSERT_TRUE(handle != nullptr) << dlerror();
+    const char** ns_public_extern_string = static_cast<const char**>(dlsym(handle, "g_public_extern_string"));
+    ASSERT_TRUE(ns_public_extern_string != nullptr) << dlerror();
+    ASSERT_STREQ("This string is from public namespace", *ns_public_extern_string);
+
+    dlclose(handle);
+  }
+
+  // 3. Check that it is still isolated.
+  {
+    void* handle = android_dlopen_ext(
+            (get_testlib_root() + "/libtest_empty.so").c_str(),
+            RTLD_NOW,
+            &extinfo);
+
+    ASSERT_TRUE(handle == nullptr);
+  }
+}
+
 TEST(dlext, ns_shared_dlclose) {
   android_set_application_target_sdk_version(42U); // something > 23
 
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index 4ff324e..0ec4663 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -247,6 +247,40 @@
 
 // mips doesn't support ifuncs
 #if !defined(__mips__)
+TEST(dlfcn, ifunc_variable) {
+  typedef const char* (*fn_ptr)();
+
+  // ifunc's choice depends on whether IFUNC_CHOICE has a value
+  // first check the set case
+  setenv("IFUNC_CHOICE", "set", 1);
+  // preload libtest_ifunc_variable_impl.so
+  void* handle_impl = dlopen("libtest_ifunc_variable_impl.so", RTLD_NOW);
+  void* handle = dlopen("libtest_ifunc_variable.so", RTLD_NOW);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+  const char** foo_ptr = reinterpret_cast<const char**>(dlsym(handle, "foo"));
+  fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
+  ASSERT_TRUE(foo_ptr != nullptr) << dlerror();
+  ASSERT_TRUE(foo_library_ptr != nullptr) << dlerror();
+  ASSERT_EQ(strncmp("set", *foo_ptr, 3), 0);
+  ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0);
+  dlclose(handle);
+  dlclose(handle_impl);
+
+  // then check the unset case
+  unsetenv("IFUNC_CHOICE");
+  handle_impl = dlopen("libtest_ifunc_variable_impl.so", RTLD_NOW);
+  handle = dlopen("libtest_ifunc_variable.so", RTLD_NOW);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+  foo_ptr = reinterpret_cast<const char**>(dlsym(handle, "foo"));
+  foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
+  ASSERT_TRUE(foo_ptr != nullptr) << dlerror();
+  ASSERT_TRUE(foo_library_ptr != nullptr) << dlerror();
+  ASSERT_EQ(strncmp("unset", *foo_ptr, 5), 0);
+  ASSERT_EQ(strncmp("unset", foo_library_ptr(), 5), 0);
+  dlclose(handle);
+  dlclose(handle_impl);
+}
+
 TEST(dlfcn, ifunc) {
   typedef const char* (*fn_ptr)();
 
@@ -254,11 +288,11 @@
   // first check the set case
   setenv("IFUNC_CHOICE", "set", 1);
   void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
-  ASSERT_TRUE(handle != nullptr);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
   fn_ptr foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
   fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
-  ASSERT_TRUE(foo_ptr != nullptr);
-  ASSERT_TRUE(foo_library_ptr != nullptr);
+  ASSERT_TRUE(foo_ptr != nullptr) << dlerror();
+  ASSERT_TRUE(foo_library_ptr != nullptr) << dlerror();
   ASSERT_EQ(strncmp("set", foo_ptr(), 3), 0);
   ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0);
   dlclose(handle);
@@ -266,13 +300,13 @@
   // then check the unset case
   unsetenv("IFUNC_CHOICE");
   handle = dlopen("libtest_ifunc.so", RTLD_NOW);
-  ASSERT_TRUE(handle != nullptr);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
   foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
   foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
-  ASSERT_TRUE(foo_ptr != nullptr);
-  ASSERT_TRUE(foo_library_ptr != nullptr);
+  ASSERT_TRUE(foo_ptr != nullptr) << dlerror();
+  ASSERT_TRUE(foo_library_ptr != nullptr) << dlerror();
   ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0);
-  ASSERT_EQ(strncmp("unset", foo_library_ptr(), 3), 0);
+  ASSERT_EQ(strncmp("unset", foo_library_ptr(), 5), 0);
   dlclose(handle);
 }
 
diff --git a/tests/elf_test.cpp b/tests/elf_test.cpp
new file mode 100644
index 0000000..ad7cdfa
--- /dev/null
+++ b/tests/elf_test.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <elf.h>
+
+#include <gtest/gtest.h>
+
+// https://github.com/android-ndk/ndk/issues/377
+TEST(elf, have_ELF_ST_INFO_macros) {
+  uint8_t info;
+
+  // 0x0f
+  info = ELF32_ST_INFO(STB_LOCAL, STT_HIPROC);
+  ASSERT_EQ(STB_LOCAL, ELF32_ST_BIND(info));
+  ASSERT_EQ(STT_HIPROC, ELF32_ST_TYPE(info));
+
+  // 0x0f
+  info = ELF64_ST_INFO(STB_LOCAL, STT_HIPROC);
+  ASSERT_EQ(STB_LOCAL, ELF64_ST_BIND(info));
+  ASSERT_EQ(STT_HIPROC, ELF64_ST_TYPE(info));
+
+  // 0xf0
+  info = ELF32_ST_INFO(STB_LOCAL, STT_HIPROC);
+  ASSERT_EQ(STB_LOCAL, ELF32_ST_BIND(info));
+  ASSERT_EQ(STT_HIPROC, ELF32_ST_TYPE(info));
+
+  // 0xf0
+  info = ELF64_ST_INFO(STB_LOCAL, STT_HIPROC);
+  ASSERT_EQ(STB_LOCAL, ELF64_ST_BIND(info));
+  ASSERT_EQ(STT_HIPROC, ELF64_ST_TYPE(info));
+}
diff --git a/tests/fortify_test.cpp b/tests/fortify_test.cpp
index 67103e1..984a657 100644
--- a/tests/fortify_test.cpp
+++ b/tests/fortify_test.cpp
@@ -219,7 +219,6 @@
 #endif // __BIONIC__
 }
 
-// this buffer overflow. TODO: Fix clang.
 TEST_F(DEATHTEST, strlcpy_fortified2) {
 #if defined(__BIONIC__)
   foo myfoo;
@@ -231,7 +230,6 @@
 #endif // __BIONIC__
 }
 
-// this buffer overflow. TODO: Fix clang.
 TEST_F(DEATHTEST, strlcat_fortified2) {
 #if defined(__BIONIC__)
   foo myfoo;
@@ -407,11 +405,8 @@
   ASSERT_FORTIFY(sprintf(buf, "%s", source_buf));
 }
 
-#ifdef __clang__
-// Exists upstream, but hasn't been pulled in yet.
-#if __has_attribute(alloc_size)
-#error "Reenable this test"
-#endif
+#ifdef __clang__ && !__has_attribute(alloc_size)
+// TODO: remove this after Clang prebuilt rebase.
 #else
 // This test is disabled in clang because clang doesn't properly detect
 // this buffer overflow. TODO: Fix clang.
diff --git a/tests/libc_logging_test.cpp b/tests/libc_logging_test.cpp
deleted file mode 100644
index 4150483..0000000
--- a/tests/libc_logging_test.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gtest/gtest.h>
-
-#if defined(__BIONIC__)
-#include "../libc/bionic/libc_logging.cpp"
-extern int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...);
-#endif // __BIONIC__
-
-TEST(libc_logging, smoke) {
-#if defined(__BIONIC__)
-  char buf[BUFSIZ];
-
-  __libc_format_buffer(buf, sizeof(buf), "a");
-  EXPECT_STREQ("a", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "%%");
-  EXPECT_STREQ("%", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "01234");
-  EXPECT_STREQ("01234", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%sb", "01234");
-  EXPECT_STREQ("a01234b", buf);
-
-  char* s = NULL;
-  __libc_format_buffer(buf, sizeof(buf), "a%sb", s);
-  EXPECT_STREQ("a(null)b", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "aa%scc", "bb");
-  EXPECT_STREQ("aabbcc", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%cc", 'b');
-  EXPECT_STREQ("abc", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%db", 1234);
-  EXPECT_STREQ("a1234b", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%db", -8123);
-  EXPECT_STREQ("a-8123b", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%hdb", static_cast<short>(0x7fff0010));
-  EXPECT_STREQ("a16b", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%hhdb", static_cast<char>(0x7fffff10));
-  EXPECT_STREQ("a16b", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%lldb", 0x1000000000LL);
-  EXPECT_STREQ("a68719476736b", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%ldb", 70000L);
-  EXPECT_STREQ("a70000b", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%pb", reinterpret_cast<void*>(0xb0001234));
-  EXPECT_STREQ("a0xb0001234b", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%xz", 0x12ab);
-  EXPECT_STREQ("a12abz", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%Xz", 0x12ab);
-  EXPECT_STREQ("a12ABz", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%08xz", 0x123456);
-  EXPECT_STREQ("a00123456z", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%5dz", 1234);
-  EXPECT_STREQ("a 1234z", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%05dz", 1234);
-  EXPECT_STREQ("a01234z", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%8dz", 1234);
-  EXPECT_STREQ("a    1234z", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%-8dz", 1234);
-  EXPECT_STREQ("a1234    z", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "A%-11sZ", "abcdef");
-  EXPECT_STREQ("Aabcdef     Z", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "A%s:%dZ", "hello", 1234);
-  EXPECT_STREQ("Ahello:1234Z", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%03d:%d:%02dz", 5, 5, 5);
-  EXPECT_STREQ("a005:5:05z", buf);
-
-  void* p = NULL;
-  __libc_format_buffer(buf, sizeof(buf), "a%d,%pz", 5, p);
-  EXPECT_STREQ("a5,0x0z", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%lld,%d,%d,%dz", 0x1000000000LL, 6, 7, 8);
-  EXPECT_STREQ("a68719476736,6,7,8z", buf);
-#else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif // __BIONIC__
-}
-
-TEST(libc_logging, d_INT_MAX) {
-#if defined(__BIONIC__)
-  char buf[BUFSIZ];
-  __libc_format_buffer(buf, sizeof(buf), "%d", INT_MAX);
-  EXPECT_STREQ("2147483647", buf);
-#else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif // __BIONIC__
-}
-
-TEST(libc_logging, d_INT_MIN) {
-#if defined(__BIONIC__)
-  char buf[BUFSIZ];
-  __libc_format_buffer(buf, sizeof(buf), "%d", INT_MIN);
-  EXPECT_STREQ("-2147483648", buf);
-#else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif // __BIONIC__
-}
-
-TEST(libc_logging, ld_LONG_MAX) {
-#if defined(__BIONIC__)
-  char buf[BUFSIZ];
-  __libc_format_buffer(buf, sizeof(buf), "%ld", LONG_MAX);
-#if defined(__LP64__)
-  EXPECT_STREQ("9223372036854775807", buf);
-#else
-  EXPECT_STREQ("2147483647", buf);
-#endif
-#else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif // __BIONIC__
-}
-
-TEST(libc_logging, ld_LONG_MIN) {
-#if defined(__BIONIC__)
-  char buf[BUFSIZ];
-  __libc_format_buffer(buf, sizeof(buf), "%ld", LONG_MIN);
-#if defined(__LP64__)
-  EXPECT_STREQ("-9223372036854775808", buf);
-#else
-  EXPECT_STREQ("-2147483648", buf);
-#endif
-#else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif // __BIONIC__
-}
-
-TEST(libc_logging, lld_LLONG_MAX) {
-#if defined(__BIONIC__)
-  char buf[BUFSIZ];
-  __libc_format_buffer(buf, sizeof(buf), "%lld", LLONG_MAX);
-  EXPECT_STREQ("9223372036854775807", buf);
-#else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif // __BIONIC__
-}
-
-TEST(libc_logging, lld_LLONG_MIN) {
-#if defined(__BIONIC__)
-  char buf[BUFSIZ];
-  __libc_format_buffer(buf, sizeof(buf), "%lld", LLONG_MIN);
-  EXPECT_STREQ("-9223372036854775808", buf);
-#else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif // __BIONIC__
-}
-
-TEST(libc_logging, buffer_overrun) {
-#if defined(__BIONIC__)
-  char buf[BUFSIZ];
-  ASSERT_EQ(11, __libc_format_buffer(buf, sizeof(buf), "hello %s", "world"));
-  EXPECT_STREQ("hello world", buf);
-  ASSERT_EQ(11, __libc_format_buffer(buf, 8, "hello %s", "world"));
-  EXPECT_STREQ("hello w", buf);
-#else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif // __BIONIC__
-}
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index a031fe9..973a8d2 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -272,10 +272,8 @@
 cc_test_library {
     name: "libtest_ifunc",
     defaults: ["bionic_testlib_defaults"],
-    srcs: ["dlopen_testlib_ifunc.c"],
+    srcs: ["dlopen_testlib_ifunc.cpp"],
 
-    // TODO(dimitry): clang does not support ifunc attribute
-    clang: false,
     arch: {
         mips: {
             enabled: false,
@@ -284,6 +282,64 @@
             enabled: false,
         },
     },
+
+    target: {
+        android: {
+            shared_libs: ["libdl"],
+        },
+        host: {
+            host_ldlibs: ["-ldl"],
+        },
+    },
+}
+
+cc_test_library {
+    name: "libtest_ifunc_variable",
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["dlopen_testlib_ifunc_variable.cpp"],
+    shared_libs: [ "libtest_ifunc_variable_impl" ],
+
+    arch: {
+        mips: {
+            enabled: false,
+        },
+        mips64: {
+            enabled: false,
+        },
+    },
+
+    target: {
+        android: {
+            shared_libs: ["libdl"],
+        },
+        host: {
+            host_ldlibs: ["-ldl"],
+        },
+    },
+}
+
+cc_test_library {
+    name: "libtest_ifunc_variable_impl",
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["dlopen_testlib_ifunc_variable_impl.cpp"],
+
+    arch: {
+        mips: {
+            enabled: false,
+        },
+        mips64: {
+            enabled: false,
+        },
+    },
+
+    target: {
+        android: {
+            shared_libs: ["libdl"],
+        },
+        host: {
+            host_ldlibs: ["-ldl"],
+        },
+    },
 }
 
 // -----------------------------------------------------------------------------
diff --git a/tests/libs/bionic_tests_zipalign.cpp b/tests/libs/bionic_tests_zipalign.cpp
index 8e31474..56183ba 100644
--- a/tests/libs/bionic_tests_zipalign.cpp
+++ b/tests/libs/bionic_tests_zipalign.cpp
@@ -142,7 +142,7 @@
   if (return_value != 0) {
     CloseArchive(handle);
     fprintf(stderr, "Unable to open '%s': %s\n", argv[2], ErrorCodeString(return_value));
-    return false;
+    return 1;
   }
 
   FILE* zip_dst = fopen(argv[3], "we");
diff --git a/tests/libs/dlopen_testlib_ifunc.c b/tests/libs/dlopen_testlib_ifunc.cpp
similarity index 65%
rename from tests/libs/dlopen_testlib_ifunc.c
rename to tests/libs/dlopen_testlib_ifunc.cpp
index b68a3dd..f8acba7 100644
--- a/tests/libs/dlopen_testlib_ifunc.c
+++ b/tests/libs/dlopen_testlib_ifunc.cpp
@@ -14,52 +14,56 @@
  * limitations under the License.
  */
 
+#include <dlfcn.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 
-static int g_flag = 0;
+static uintptr_t g_flag = 0;
 
 static void __attribute__((constructor)) init_flag() {
-  g_flag = 1;
+  g_flag = reinterpret_cast<uintptr_t>(dlsym(RTLD_DEFAULT, "dlsym"));
 }
 
 static const char* is_ctor_called() __attribute__ ((ifunc("is_ctor_called_ifun")));
 
-const char* foo() __attribute__ ((ifunc ("foo_ifunc")));
+extern "C" const char* foo() __attribute__ ((ifunc ("foo_ifunc")));
 
 // Static linker creates GLOBAL/IFUNC symbol and JUMP_SLOT relocation type for plt segment
-const char* is_ctor_called_jump_slot() __attribute__ ((ifunc("is_ctor_called_ifun")));
+extern "C" const char* is_ctor_called_jump_slot() __attribute__ ((ifunc("is_ctor_called_ifun")));
 
-const char* is_ctor_called_irelative() {
+extern "C" const char* is_ctor_called_irelative() {
   // Call internal ifunc-resolved function with IRELATIVE reloc
   return is_ctor_called();
 }
 
-const char* return_true() {
+extern "C" const char* return_true() {
   return "true";
 }
 
-const char* return_false() {
+extern "C" const char* return_false() {
   return "false";
 }
 
-const char* f1() {
+extern "C" const char* f1() {
   return "unset";
 }
 
-const char* f2() {
+extern "C" const char* f2() {
   return "set";
 }
 
-void* is_ctor_called_ifun() {
+typedef const char* (*fn_ptr)();
+
+extern "C" fn_ptr is_ctor_called_ifun() {
   return g_flag == 0 ? return_false : return_true;
 }
 
-void* foo_ifunc() {
+extern "C" fn_ptr foo_ifunc() {
    char* choice = getenv("IFUNC_CHOICE");
    return choice == NULL ? f1 : f2;
 }
 
-const char* foo_library() {
+extern "C" const char* foo_library() {
    return foo();
 }
diff --git a/tests/libs/dlopen_testlib_ifunc_variable.cpp b/tests/libs/dlopen_testlib_ifunc_variable.cpp
new file mode 100644
index 0000000..a1f1ab6
--- /dev/null
+++ b/tests/libs/dlopen_testlib_ifunc_variable.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+extern "C" const char* foo;
+
+extern "C" const char* foo_library() {
+   return foo;
+}
diff --git a/tests/libs/dlopen_testlib_ifunc_variable_impl.cpp b/tests/libs/dlopen_testlib_ifunc_variable_impl.cpp
new file mode 100644
index 0000000..a550fef
--- /dev/null
+++ b/tests/libs/dlopen_testlib_ifunc_variable_impl.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dlfcn.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static uintptr_t g_flag = 0;
+
+static void __attribute__((constructor)) init_flag() {
+  g_flag = reinterpret_cast<uintptr_t>(dlsym(RTLD_DEFAULT, "dlsym"));
+}
+
+static const char* is_ctor_called() __attribute__ ((ifunc("is_ctor_called_ifun")));
+
+extern "C" const char* foo() __attribute__ ((ifunc ("foo_ifunc")));
+
+// Static linker creates GLOBAL/IFUNC symbol and JUMP_SLOT relocation type for plt segment
+extern "C" const char* is_ctor_called_jump_slot() __attribute__ ((ifunc("is_ctor_called_ifun")));
+
+extern "C" const char* is_ctor_called_irelative() {
+  // Call internal ifunc-resolved function with IRELATIVE reloc
+  return is_ctor_called();
+}
+
+extern "C" const char* var_true = "true";
+extern "C" const char* var_false = "false";
+
+extern "C" const char* v1 = "unset";
+extern "C" const char* v2 = "set";
+
+extern "C" void* is_ctor_called_ifun() {
+  return g_flag == 0 ? &var_false : &var_true;
+}
+
+extern "C" void* foo_ifunc() {
+   char* choice = getenv("IFUNC_CHOICE");
+   return choice == NULL ? &v1 : &v2;
+}
diff --git a/tests/link_test.cpp b/tests/link_test.cpp
new file mode 100644
index 0000000..ac3ccb9
--- /dev/null
+++ b/tests/link_test.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <gtest/gtest.h>
+
+#include <link.h>
+
+TEST(link, dl_iterate_phdr_early_exit) {
+  static size_t call_count = 0;
+  ASSERT_EQ(123, dl_iterate_phdr([](dl_phdr_info*, size_t, void*) { ++call_count; return 123; },
+                                 nullptr));
+  ASSERT_EQ(1u, call_count);
+}
+
+TEST(link, dl_iterate_phdr) {
+  struct Functor {
+    static int Callback(dl_phdr_info* i, size_t s, void* data) {
+      reinterpret_cast<Functor*>(data)->DoChecks(i, s);
+      return 0;
+    }
+    void DoChecks(dl_phdr_info* info, size_t s) {
+      ASSERT_EQ(sizeof(dl_phdr_info), s);
+
+      // TODO: why does the entry for the main executable have a null dlpi_addr and no name anyway?
+      if (++count == 1 && info->dlpi_addr == 0) return;
+
+      ASSERT_TRUE(info->dlpi_name != nullptr);
+
+      // Find the first PT_LOAD program header so we can find the ELF header.
+      for (ElfW(Half) i = 0; i < info->dlpi_phnum; ++i) {
+        const ElfW(Phdr)* phdr = reinterpret_cast<const ElfW(Phdr)*>(&info->dlpi_phdr[i]);
+        if (phdr->p_type == PT_LOAD) {
+          const ElfW(Ehdr)* ehdr = reinterpret_cast<const ElfW(Ehdr)*>(info->dlpi_addr +
+                                                                       phdr->p_vaddr);
+          // Does it look like an ELF file?
+          ASSERT_EQ(0, memcmp(ehdr, ELFMAG, SELFMAG));
+          // Does the e_phnum match what dl_iterate_phdr told us?
+          ASSERT_EQ(info->dlpi_phnum, ehdr->e_phnum);
+          break;
+        }
+      }
+    }
+    size_t count;
+  } f = {};
+  ASSERT_EQ(0, dl_iterate_phdr(Functor::Callback, &f));
+}
+
+#if __arm__
+static uintptr_t read_exidx_func(uintptr_t* entry) {
+  int32_t offset = *entry;
+  // Sign-extend from int31 to int32.
+  if ((offset & 0x40000000) != 0) {
+    offset += -0x7fffffff - 1;
+  }
+  return reinterpret_cast<uintptr_t>(entry) + offset;
+}
+__attribute__((__unused__)) static void another_function_in_same_ELF_file() {}
+#endif
+
+TEST(link, dl_unwind_find_exidx) {
+#if __arm__
+  int count = 0;
+  struct eit_entry_t {
+    uintptr_t one;
+    uintptr_t two;
+  };
+  eit_entry_t* entries = reinterpret_cast<eit_entry_t*>(dl_unwind_find_exidx(
+      reinterpret_cast<_Unwind_Ptr>(read_exidx_func), &count));
+  ASSERT_TRUE(entries != nullptr);
+  ASSERT_GT(count, 0);
+
+  // Sanity checks
+  uintptr_t func = reinterpret_cast<uintptr_t>(read_exidx_func);
+  bool found = false;
+  for (int i = 0; i < count; ++i) {
+    // Entries must have bit 31 clear.
+    ASSERT_TRUE((entries[i].one & (1<<31)) == 0);
+
+    uintptr_t exidx_func = read_exidx_func(&entries[i].one);
+
+    // If our function is compiled for thumb, exception table contains our address - 1.
+    if (func == exidx_func || func == exidx_func + 1) found = true;
+
+    // Entries must be sorted. Some addresses may appear twice if function
+    // is compiled for arm.
+    if (i > 0) {
+      EXPECT_GE(exidx_func, read_exidx_func(&entries[i - 1].one)) << i;
+    }
+  }
+  ASSERT_TRUE(found);
+#else
+  GTEST_LOG_(INFO) << "dl_unwind_find_exidx is an ARM-only API\n";
+#endif
+}
diff --git a/tests/linux_swab_test.cpp b/tests/linux_swab_test.cpp
new file mode 100644
index 0000000..6b964dc
--- /dev/null
+++ b/tests/linux_swab_test.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <linux/swab.h>
+
+// This test makes sure that references to all of the kernel swab
+// macros/inline functions that are exported work properly.
+// Verifies that any kernel header updates do not break these macros.
+TEST(swab, fswa) {
+  EXPECT_EQ(0x3412U, __swab16(0x1234));
+  EXPECT_EQ(0x78563412U, __swab32(0x12345678U));
+  EXPECT_EQ(0xbaefcdab78563412ULL, __swab64(0x12345678abcdefbaULL));
+
+  __u16 bval16 = 0x1234;
+  EXPECT_EQ(0x3412U, __swab16p(&bval16));
+  __u32 bval32 = 0x12345678U;
+  EXPECT_EQ(0x78563412U, __swab32p(&bval32));
+  __u64 bval64 = 0x12345678abcdefbaULL;
+  EXPECT_EQ(0xbaefcdab78563412ULL, __swab64p(&bval64));
+
+  __u16 sval16 = 0x1234;
+  __swab16s(&sval16);
+  EXPECT_EQ(0x3412U, sval16);
+  __u32 sval32 = 0x12345678U;
+  __swab32s(&sval32);
+  EXPECT_EQ(0x78563412U, sval32);
+  __u64 sval64 = 0x12345678abcdefbaULL;
+  __swab64s(&sval64);
+  EXPECT_EQ(0xbaefcdab78563412ULL, sval64);
+
+  EXPECT_EQ(0x56781234U, __swahw32(0x12345678U));
+  EXPECT_EQ(0x34127856U, __swahb32(0x12345678U));
+
+  __u32 hval32 = 0x12345678U;
+  EXPECT_EQ(0x56781234U, __swahw32p(&hval32));
+  hval32 = 0x12345678U;
+  EXPECT_EQ(0x34127856U, __swahb32p(&hval32));
+
+  __u32 hsval32 = 0x12345678U;
+  __swahw32s(&hsval32);
+  EXPECT_EQ(0x56781234U, hsval32);
+  hsval32 = 0x12345678U;
+  __swahb32s(&hsval32);
+  EXPECT_EQ(0x34127856U, hsval32);
+}
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index 87b4c81..d64bc48 100755
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -1963,8 +1963,9 @@
     } else {
       ASSERT_EQ(0, result);
     }
-    arg->data->finished_mask |= (1 << arg->id);
-    if (arg->data->finished_mask == ((1 << arg->data->thread_count) - 1)) {
+    int mask = arg->data->finished_mask.fetch_or(1 << arg->id);
+    mask |= 1 << arg->id;
+    if (mask == ((1 << arg->data->thread_count) - 1)) {
       ASSERT_EQ(1, arg->data->serial_thread_count);
       arg->data->finished_iteration_count++;
       arg->data->finished_mask = 0;
diff --git a/tests/sys_ptrace_test.cpp b/tests/sys_ptrace_test.cpp
index 69638be..00322ec 100644
--- a/tests/sys_ptrace_test.cpp
+++ b/tests/sys_ptrace_test.cpp
@@ -266,7 +266,7 @@
   ASSERT_EQ(0, sigaction(SIGALRM, &action, &oldaction)) << strerror(errno);
   alarm(5);
 
-  run_watchpoint_test<Uint128_t>(watchpoint_imprecise_child, 8, 8);
+  run_watchpoint_test<Uint128_t>(watchpoint_imprecise_child, 8, sizeof(void*));
 
   ASSERT_EQ(0, sigaction(SIGALRM, &oldaction, nullptr)) << strerror(errno);
 }
diff --git a/tools/versioner/src/Driver.cpp b/tools/versioner/src/Driver.cpp
index 215dc3c..1b631b6 100644
--- a/tools/versioner/src/Driver.cpp
+++ b/tools/versioner/src/Driver.cpp
@@ -42,6 +42,7 @@
 #include <llvm/ADT/IntrusiveRefCntPtr.h>
 #include <llvm/ADT/SmallVector.h>
 #include <llvm/ADT/StringRef.h>
+#include <llvm/Config/config.h>
 
 #include "Arch.h"
 #include "DeclarationDatabase.h"
@@ -237,7 +238,14 @@
   }
 
   clang::CompilerInstance Compiler;
+
+// Remove the workaround once b/35936936 is fixed.
+#if LLVM_VERSION_MAJOR >= 5
+  Compiler.setInvocation(std::move(invocation));
+#else
   Compiler.setInvocation(invocation.release());
+#endif
+
   Compiler.setDiagnostics(diags.get());
   Compiler.setVirtualFileSystem(vfs);
 
diff --git a/tools/versioner/src/versioner.cpp b/tools/versioner/src/versioner.cpp
index b551709..735ea04 100644
--- a/tools/versioner/src/versioner.cpp
+++ b/tools/versioner/src/versioner.cpp
@@ -446,6 +446,12 @@
   }
 }
 
+// versioner uses a prebuilt version of clang, which is not up-to-date wrt/
+// container annotations. So disable container overflow checking. b/37775238
+extern "C" const char* __asan_default_options() {
+  return "detect_container_overflow=0";
+}
+
 int main(int argc, char** argv) {
   std::string cwd = getWorkingDir() + "/";
   bool default_args = true;