Merge changes Iba5f74e1,I92b88939

* changes:
  Fix CtsJniTestCases
  Fix formatting
diff --git a/libc/Android.bp b/libc/Android.bp
index 182e8f7..0950662 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -2425,3 +2425,54 @@
         static_libs: ["libbase"],
     },
 }
+
+// This is a temporary library that will use scudo as the native memory
+// allocator. To use it, add it as the first shared library.
+cc_library_shared {
+    name: "libc_scudo",
+    vendor_available: true,
+    srcs: [
+        "bionic/malloc_common.cpp",
+        "bionic/malloc_common_dynamic.cpp",
+        "bionic/malloc_heapprofd.cpp",
+        "bionic/malloc_limit.cpp",
+        "bionic/scudo_wrapper.cpp",
+        "bionic/__set_errno.cpp",
+    ],
+    cflags: ["-DUSE_SCUDO"],
+    stl: "none",
+    system_shared_libs: [],
+
+    header_libs: ["libc_headers"],
+
+    static_libs: ["libasync_safe"],
+
+    allow_undefined_symbols: true,
+    shared_libs: ["libscudo_wrapper"],
+
+    arch: {
+        arm: {
+            srcs: ["arch-arm/syscalls/__rt_sigprocmask.S"],
+        },
+        arm64: {
+            srcs: ["arch-arm64/syscalls/__rt_sigprocmask.S"],
+        },
+        x86: {
+            srcs: [
+                "arch-x86/bionic/__libc_init_sysinfo.cpp",
+                "arch-x86/syscalls/__rt_sigprocmask.S",
+            ],
+        },
+        x86_64: {
+            srcs: ["arch-x86_64/syscalls/__rt_sigprocmask.S"],
+        },
+    },
+
+    // Mark this library as global so it overrides all the allocation
+    // definitions properly.
+    ldflags: ["-Wl,-z,global"],
+}
+
+subdirs = [
+    "bionic/scudo",
+]
diff --git a/libc/bionic/bionic_allocator.cpp b/libc/bionic/bionic_allocator.cpp
index da0f7d0..168d6ba 100644
--- a/libc/bionic/bionic_allocator.cpp
+++ b/libc/bionic/bionic_allocator.cpp
@@ -45,11 +45,11 @@
 
 //
 // BionicAllocator is a general purpose allocator designed to provide the same
-// functionality as the malloc/free/realloc libc functions.
+// functionality as the malloc/free/realloc/memalign libc functions.
 //
 // On alloc:
-// If size is >= 1k allocator proxies malloc call directly to mmap
-// If size < 1k allocator uses SmallObjectAllocator for the size
+// If size is > 1k allocator proxies malloc call directly to mmap.
+// If size <= 1k allocator uses BionicSmallObjectAllocator for the size
 // rounded up to the nearest power of two.
 //
 // On free:
@@ -57,10 +57,10 @@
 // For a pointer allocated using proxy-to-mmap allocator unmaps
 // the memory.
 //
-// For a pointer allocated using SmallObjectAllocator it adds
+// For a pointer allocated using BionicSmallObjectAllocator it adds
 // the block to free_blocks_list in the corresponding page. If the number of
-// free pages reaches 2, SmallObjectAllocator munmaps one of the pages keeping
-// the other one in reserve.
+// free pages reaches 2, BionicSmallObjectAllocator munmaps one of the pages
+// keeping the other one in reserve.
 
 // Memory management for large objects is fairly straightforward, but for small
 // objects it is more complicated.  If you are changing this code, one simple
diff --git a/libc/bionic/malloc_common.h b/libc/bionic/malloc_common.h
index a40501d..7f3b711 100644
--- a/libc/bionic/malloc_common.h
+++ b/libc/bionic/malloc_common.h
@@ -55,11 +55,20 @@
 
 #else // __has_feature(hwaddress_sanitizer)
 
+#if defined(USE_SCUDO)
+
+#include "scudo.h"
+#define Malloc(function)  scudo_ ## function
+
+#else
+
 #include "jemalloc.h"
 #define Malloc(function)  je_ ## function
 
 #endif
 
+#endif
+
 extern int gMallocLeakZygoteChild;
 
 static inline const MallocDispatch* GetDispatchTable() {
diff --git a/libc/bionic/malloc_common_dynamic.cpp b/libc/bionic/malloc_common_dynamic.cpp
index e12c247..3ccaed6 100644
--- a/libc/bionic/malloc_common_dynamic.cpp
+++ b/libc/bionic/malloc_common_dynamic.cpp
@@ -307,8 +307,6 @@
     atomic_store(&globals->current_dispatch_table, &globals->malloc_dispatch_table);
   }
 
-  info_log("%s: malloc %s enabled", getprogname(), prefix);
-
   // Use atexit to trigger the cleanup function. This avoids a problem
   // where another atexit function is used to cleanup allocated memory,
   // but the finalize function was already called. This particular error
@@ -316,7 +314,7 @@
   int ret_value = __cxa_atexit(MallocFiniImpl, nullptr, nullptr);
   if (ret_value != 0) {
     // We don't consider this a fatal error.
-    info_log("failed to set atexit cleanup function: %d", ret_value);
+    warning_log("failed to set atexit cleanup function: %d", ret_value);
   }
   return true;
 }
diff --git a/libc/bionic/scudo.h b/libc/bionic/scudo.h
new file mode 100644
index 0000000..d9933c4
--- /dev/null
+++ b/libc/bionic/scudo.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdio.h>
+#include <malloc.h>
+
+#include <private/bionic_config.h>
+
+__BEGIN_DECLS
+
+void* scudo_aligned_alloc(size_t, size_t);
+void* scudo_calloc(size_t, size_t);
+void scudo_free(void*);
+struct mallinfo scudo_mallinfo();
+void* scudo_malloc(size_t);
+int scudo_malloc_info(int, FILE*);
+size_t scudo_malloc_usable_size(const void*);
+int scudo_mallopt(int, int);
+void* scudo_memalign(size_t, size_t);
+void* scudo_realloc(void*, size_t);
+int scudo_posix_memalign(void**, size_t, size_t);
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
+void* scudo_pvalloc(size_t);
+void* scudo_valloc(size_t);
+#endif
+
+int scudo_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*);
+void scudo_malloc_disable();
+void scudo_malloc_enable();
+
+__END_DECLS
diff --git a/libc/bionic/scudo/Android.bp b/libc/bionic/scudo/Android.bp
new file mode 100644
index 0000000..8b518bb
--- /dev/null
+++ b/libc/bionic/scudo/Android.bp
@@ -0,0 +1,60 @@
+//
+// Copyright (C) 2019 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.
+//
+
+cc_library_shared {
+    name: "libscudo_wrapper",
+    vendor_available: true,
+    srcs: ["scudo.cpp"],
+
+    stl: "none",
+    system_shared_libs: [],
+    host_supported: false,
+
+    header_libs: ["libc_headers"],
+    include_dirs: [
+        "bionic/libc",
+        "bionic/libc/bionic",
+    ],
+
+    whole_static_libs: ["libasync_safe"],
+
+    arch: {
+        arm: {
+            whole_static_libs: ["libclang_rt.scudo_minimal-arm-android.static"],
+        },
+        arm64: {
+            whole_static_libs: ["libclang_rt.scudo_minimal-aarch64-android.static"],
+        },
+        x86: {
+            whole_static_libs: ["libclang_rt.scudo_minimal-i686-android.static"],
+        },
+        x86_64: {
+            whole_static_libs: ["libclang_rt.scudo_minimal-x86_64-android.static"],
+        },
+    },
+
+    // Will be referencing other libc code that won't be defined here.
+    allow_undefined_symbols: true,
+
+    multilib: {
+        lib32: {
+            version_script: "exported32.map",
+        },
+        lib64: {
+            version_script: "exported64.map",
+        },
+    },
+}
diff --git a/libc/bionic/scudo/exported32.map b/libc/bionic/scudo/exported32.map
new file mode 100644
index 0000000..4b6791d
--- /dev/null
+++ b/libc/bionic/scudo/exported32.map
@@ -0,0 +1,16 @@
+LIBC_SCUDO {
+  global:
+    scudo_aligned_alloc;
+    scudo_calloc;
+    scudo_free;
+    scudo_mallinfo;
+    scudo_malloc;
+    scudo_malloc_usable_size;
+    scudo_memalign;
+    scudo_posix_memalign;
+    scudo_pvalloc;
+    scudo_realloc;
+    scudo_valloc;
+  local:
+    *;
+};
diff --git a/libc/bionic/scudo/exported64.map b/libc/bionic/scudo/exported64.map
new file mode 100644
index 0000000..1346b4b
--- /dev/null
+++ b/libc/bionic/scudo/exported64.map
@@ -0,0 +1,14 @@
+LIBC_SCUDO {
+  global:
+    scudo_aligned_alloc;
+    scudo_calloc;
+    scudo_free;
+    scudo_mallinfo;
+    scudo_malloc;
+    scudo_malloc_usable_size;
+    scudo_memalign;
+    scudo_posix_memalign;
+    scudo_realloc;
+  local:
+    *;
+};
diff --git a/libc/bionic/scudo/scudo.cpp b/libc/bionic/scudo/scudo.cpp
new file mode 100644
index 0000000..fb09b92
--- /dev/null
+++ b/libc/bionic/scudo/scudo.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2019 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 <errno.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/prctl.h>
+
+#include "private/bionic_macros.h"
+
+#include "scudo.h"
+
+// Disable Scudo's mismatch allocation check, as it is being triggered
+// by some third party code.
+extern "C" const char *__scudo_default_options() {
+  return "DeallocationTypeMismatch=false";
+}
+
+static inline bool AllocTooBig(size_t bytes) {
+#if defined(__LP64__)
+  if (__predict_false(bytes > 0x10000000000ULL)) {
+#else
+  if (__predict_false(bytes > 0x80000000ULL)) {
+#endif
+    return true;
+  }
+  return false;
+}
+
+void* scudo_aligned_alloc(size_t alignment, size_t size) {
+  if (alignment == 0 || !powerof2(alignment) || (size % alignment) != 0) {
+    errno = EINVAL;
+    return nullptr;
+  }
+  if (AllocTooBig(size)) {
+    errno = ENOMEM;
+    return nullptr;
+  }
+
+  return aligned_alloc(alignment, size);
+}
+
+void* scudo_calloc(size_t item_count, size_t item_size) {
+  size_t total;
+  if (__builtin_mul_overflow(item_count, item_size, &total) || AllocTooBig(total)) {
+    errno = ENOMEM;
+    return nullptr;
+  }
+  return calloc(item_count, item_size);
+}
+
+void scudo_free(void* ptr) {
+  free(ptr);
+}
+
+extern "C" size_t __sanitizer_get_current_allocated_bytes();
+extern "C" size_t __sanitizer_get_heap_size();
+
+struct mallinfo scudo_mallinfo() {
+  struct mallinfo info {};
+  info.uordblks = __sanitizer_get_current_allocated_bytes();
+  info.hblkhd = __sanitizer_get_heap_size();
+  info.usmblks = info.hblkhd;
+  return info;
+}
+
+void* scudo_malloc(size_t byte_count) {
+  if (AllocTooBig(byte_count)) {
+    errno = ENOMEM;
+    return nullptr;
+  }
+  return malloc(byte_count);
+}
+
+size_t scudo_malloc_usable_size(const void* ptr) {
+  return malloc_usable_size(ptr);
+}
+
+void* scudo_memalign(size_t alignment, size_t byte_count) {
+  if (AllocTooBig(byte_count)) {
+    errno = ENOMEM;
+    return nullptr;
+  }
+  if (alignment != 0) {
+    if (!powerof2(alignment)) {
+      alignment = BIONIC_ROUND_UP_POWER_OF_2(alignment);
+    }
+  } else {
+    alignment = 1;
+  }
+  return memalign(alignment, byte_count);
+}
+
+void* scudo_realloc(void* ptr, size_t byte_count) {
+  if (AllocTooBig(byte_count)) {
+    errno = ENOMEM;
+    return nullptr;
+  }
+  return realloc(ptr, byte_count);
+}
+
+int scudo_posix_memalign(void** memptr, size_t alignment, size_t size) {
+  if (alignment < sizeof(void*) || !powerof2(alignment)) {
+    return EINVAL;
+  }
+  if (AllocTooBig(size)) {
+    return ENOMEM;
+  }
+  return posix_memalign(memptr, alignment, size);
+}
+
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
+extern "C" void* pvalloc(size_t);
+
+void* scudo_pvalloc(size_t size) {
+  if (AllocTooBig(size)) {
+    errno = ENOMEM;
+    return nullptr;
+  }
+  return pvalloc(size);
+}
+
+extern "C" void* valloc(size_t);
+
+void* scudo_valloc(size_t size) {
+  if (AllocTooBig(size)) {
+    errno = ENOMEM;
+    return nullptr;
+  }
+  return valloc(size);
+}
+#endif
+
+// Do not try and name the scudo maps by overriding __sanitizer::internal_mmap.
+// There is already a function called MmapNamed that names the maps.
+// Unfortunately, there is no easy way to override MmapNamed because
+// too much of the code is not compiled into functions available in the
+// library, and the code is complicated.
diff --git a/libc/bionic/scudo_wrapper.cpp b/libc/bionic/scudo_wrapper.cpp
new file mode 100644
index 0000000..e17f20b
--- /dev/null
+++ b/libc/bionic/scudo_wrapper.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 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 <errno.h>
+#include <stdio.h>
+
+#include "scudo.h"
+#include "private/bionic_globals.h"
+#include "private/WriteProtected.h"
+
+__LIBC_HIDDEN__ WriteProtected<libc_globals> __libc_globals;
+
+#if defined(__i386__)
+__LIBC_HIDDEN__ void* __libc_sysinfo = reinterpret_cast<void*>(__libc_int0x80);
+#endif
+
+int scudo_mallopt(int /*param*/, int /*value*/) {
+  return 0;
+}
+
+int scudo_malloc_info(int /*options*/, FILE* /*fp*/) {
+  errno = ENOTSUP;
+  return -1;
+}
+
+int scudo_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*) {
+  return 0;
+}
+
+void scudo_malloc_disable() {
+}
+
+void scudo_malloc_enable() {
+}
diff --git a/libc/malloc_debug/Config.cpp b/libc/malloc_debug/Config.cpp
index dd20b5c..dbd3eac 100644
--- a/libc/malloc_debug/Config.cpp
+++ b/libc/malloc_debug/Config.cpp
@@ -135,6 +135,9 @@
     {
         "abort_on_error", {ABORT_ON_ERROR, &Config::VerifyValueEmpty},
     },
+    {
+        "verbose", {VERBOSE, &Config::VerifyValueEmpty},
+    },
 };
 
 bool Config::ParseValue(const std::string& option, const std::string& value, size_t min_value,
diff --git a/libc/malloc_debug/Config.h b/libc/malloc_debug/Config.h
index 011dc77..1b5c748 100644
--- a/libc/malloc_debug/Config.h
+++ b/libc/malloc_debug/Config.h
@@ -45,6 +45,7 @@
 constexpr uint64_t RECORD_ALLOCS = 0x200;
 constexpr uint64_t BACKTRACE_FULL = 0x400;
 constexpr uint64_t ABORT_ON_ERROR = 0x800;
+constexpr uint64_t VERBOSE = 0x1000;
 
 // In order to guarantee posix compliance, set the minimum alignment
 // to 8 bytes for 32 bit systems and 16 bytes for 64 bit systems.
diff --git a/libc/malloc_debug/PointerData.cpp b/libc/malloc_debug/PointerData.cpp
index 6c7d8fa..617d128 100644
--- a/libc/malloc_debug/PointerData.cpp
+++ b/libc/malloc_debug/PointerData.cpp
@@ -105,8 +105,10 @@
       error_log("Unable to set up backtrace signal enable function: %s", strerror(errno));
       return false;
     }
-    info_log("%s: Run: 'kill -%d %d' to enable backtracing.", getprogname(),
-             config.backtrace_signal(), getpid());
+    if (config.options() & VERBOSE) {
+      info_log("%s: Run: 'kill -%d %d' to enable backtracing.", getprogname(),
+               config.backtrace_signal(), getpid());
+    }
   }
 
   if (config.options() & BACKTRACE) {
@@ -117,8 +119,10 @@
       error_log("Unable to set up backtrace dump signal function: %s", strerror(errno));
       return false;
     }
-    info_log("%s: Run: 'kill -%d %d' to dump the backtrace.", getprogname(),
-             config.backtrace_dump_signal(), getpid());
+    if (config.options() & VERBOSE) {
+      info_log("%s: Run: 'kill -%d %d' to dump the backtrace.", getprogname(),
+               config.backtrace_dump_signal(), getpid());
+    }
   }
 
   backtrace_dump_ = false;
diff --git a/libc/malloc_debug/README.md b/libc/malloc_debug/README.md
index 93b9b1e..bebc1c1 100644
--- a/libc/malloc_debug/README.md
+++ b/libc/malloc_debug/README.md
@@ -401,6 +401,21 @@
 **NOTE**: If leak\_track is enabled, no abort occurs if leaks have been
 detected when the process is exiting.
 
+### verbose
+As of Android Q, all info messages will be turned off by default. For example,
+in Android P and older, enabling malloc debug would result in this message
+in the log:
+
+    08-16 15:54:16.060 26947 26947 I libc    : /system/bin/app_process64: malloc debug enabled
+
+In android Q, this message will not be displayed because these info messages
+slow down process start up. However, if you want to re-enable these messages,
+add the verbose option. All of the "Run XXX" messages are also silenced unless
+the verbose option is specified. This is an example of the type
+of messages that are no longer displayed:
+
+    09-10 01:03:50.070   557   557 I malloc_debug: /system/bin/audioserver: Run: 'kill -47 557' to dump the backtrace.
+
 Additional Errors
 -----------------
 There are a few other error messages that might appear in the log.
diff --git a/libc/malloc_debug/RecordData.cpp b/libc/malloc_debug/RecordData.cpp
index aea2513..5c550c0 100644
--- a/libc/malloc_debug/RecordData.cpp
+++ b/libc/malloc_debug/RecordData.cpp
@@ -181,8 +181,10 @@
   }
   pthread_setspecific(key_, nullptr);
 
-  info_log("%s: Run: 'kill -%d %d' to dump the allocation records.", getprogname(),
-           config.record_allocs_signal(), getpid());
+  if (config.options() & VERBOSE) {
+    info_log("%s: Run: 'kill -%d %d' to dump the allocation records.", getprogname(),
+             config.record_allocs_signal(), getpid());
+  }
 
   num_entries_ = config.record_allocs_num_entries();
   entries_ = new const RecordEntry*[num_entries_];
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index 093bdee..1145796 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -30,6 +30,7 @@
 #include <inttypes.h>
 #include <malloc.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <sys/cdefs.h>
 #include <sys/param.h>
@@ -252,6 +253,10 @@
   // of different error cases.
   backtrace_startup();
 
+  if (g_debug->config().options() & VERBOSE) {
+    info_log("%s: malloc debug enabled", getprogname());
+  }
+
   return true;
 }
 
diff --git a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
index fb54ee5..42d1415 100644
--- a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
@@ -743,3 +743,21 @@
       "which does not take a value\n");
   ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
 }
+
+TEST_F(MallocDebugConfigTest, verbose) {
+  ASSERT_TRUE(InitConfig("verbose")) << getFakeLogPrint();
+  ASSERT_EQ(VERBOSE, config->options());
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, trigger_verbose_fail) {
+  ASSERT_FALSE(InitConfig("verbose=200")) << getFakeLogPrint();
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string log_msg(
+      "6 malloc_debug malloc_testing: value set for option 'verbose' "
+      "which does not take a value\n");
+  ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
+}
diff --git a/libc/malloc_debug/tests/malloc_debug_system_tests.cpp b/libc/malloc_debug/tests/malloc_debug_system_tests.cpp
index 4fcd04c..71e8ebf 100644
--- a/libc/malloc_debug/tests/malloc_debug_system_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_system_tests.cpp
@@ -195,7 +195,7 @@
 
 TEST(MallocDebugSystemTest, smoke) {
   pid_t pid;
-  ASSERT_NO_FATAL_FAILURE(Exec("MallocTests.DISABLED_smoke", "backtrace", &pid));
+  ASSERT_NO_FATAL_FAILURE(Exec("MallocTests.DISABLED_smoke", "verbose backtrace", &pid));
 
   ASSERT_NO_FATAL_FAILURE(FindStrings(pid, std::vector<const char*>{"malloc debug enabled"}));
 }
@@ -399,7 +399,7 @@
     pid_t pid;
     SCOPED_TRACE(testing::Message() << functions[i].name << " expected size " << functions[i].size);
     std::string test = std::string("MallocTests.DISABLED_") + test_prefix + functions[i].name;
-    EXPECT_NO_FATAL_FAILURE(Exec(test.c_str(), "backtrace leak_track", &pid));
+    EXPECT_NO_FATAL_FAILURE(Exec(test.c_str(), "verbose backtrace leak_track", &pid));
 
     std::string expected_leak = android::base::StringPrintf("leaked block of size %zu at", functions[i].size);
     EXPECT_NO_FATAL_FAILURE(FindStrings(
diff --git a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
index 66955db..f611f3d 100644
--- a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
@@ -154,7 +154,7 @@
   return diff;
 }
 
-void VerifyAllocCalls(bool backtrace_enabled) {
+void VerifyAllocCalls(bool all_options) {
   size_t alloc_size = 1024;
 
   // Verify debug_malloc.
@@ -209,21 +209,28 @@
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   std::string expected_log;
-  if (backtrace_enabled) {
+  if (all_options) {
+    expected_log += android::base::StringPrintf(
+        "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to enable backtracing.\n",
+        SIGRTMAX - 19, getpid());
     expected_log += android::base::StringPrintf(
         "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
         SIGRTMAX - 17, getpid());
+    expected_log += android::base::StringPrintf(
+        "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the allocation records.\n",
+        SIGRTMAX - 18, getpid());
   }
+  expected_log += "4 malloc_debug malloc_testing: malloc debug enabled\n";
   ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
 }
 
 TEST_F(MallocDebugTest, fill_generic) {
-  Init("fill");
+  Init("verbose fill");
   VerifyAllocCalls(false);
 }
 
 TEST_F(MallocDebugTest, fill_on_alloc_generic) {
-  Init("fill_on_alloc");
+  Init("verbose fill_on_alloc");
   VerifyAllocCalls(false);
 }
 
@@ -241,6 +248,46 @@
   ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
+TEST_F(MallocDebugTest, verbose_only) {
+  Init("verbose");
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("4 malloc_debug malloc_testing: malloc debug enabled\n", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, verbose_backtrace_enable_on_signal) {
+  Init("verbose backtrace_enable_on_signal");
+
+  std::string expected_log = android::base::StringPrintf(
+      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to enable backtracing.\n",
+      SIGRTMAX - 19, getpid());
+  expected_log += android::base::StringPrintf(
+      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
+      SIGRTMAX - 17, getpid());
+  expected_log += "4 malloc_debug malloc_testing: malloc debug enabled\n";
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, verbose_backtrace) {
+  Init("verbose backtrace");
+
+  std::string expected_log = android::base::StringPrintf(
+      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
+      SIGRTMAX - 17, getpid());
+  expected_log += "4 malloc_debug malloc_testing: malloc debug enabled\n";
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, verbose_record_allocs) {
+  Init("verbose record_allocs");
+
+  std::string expected_log = android::base::StringPrintf(
+      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the allocation records.\n",
+      SIGRTMAX - 18, getpid());
+  expected_log += "4 malloc_debug malloc_testing: malloc debug enabled\n";
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
 TEST_F(MallocDebugTest, fill_on_free) {
   Init("fill_on_free free_track free_track_backtrace_num_frames=0");
 
@@ -302,7 +349,9 @@
 }
 
 TEST_F(MallocDebugTest, all_options) {
-  Init("guard backtrace fill expand_alloc free_track leak_track");
+  Init(
+      "guard backtrace backtrace_enable_on_signal fill expand_alloc free_track leak_track "
+      "record_allocs verify_pointers abort_on_error verbose");
   VerifyAllocCalls(true);
 }
 
@@ -667,9 +716,6 @@
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
-      SIGRTMAX - 17, getpid());
-  expected_log += android::base::StringPrintf(
       "6 malloc_debug +++ malloc_testing leaked block of size 1024 at %p (leak 1 of 3)\n",
       pointer3);
   expected_log += "6 malloc_debug Backtrace at time of allocation:\n";
@@ -1096,10 +1142,7 @@
   ASSERT_EQ(0U, backtrace_size);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
-      SIGRTMAX - 17, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
 TEST_F(MallocDebugTest, get_malloc_leak_info_single) {
@@ -1143,10 +1186,7 @@
   debug_free(pointer);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
-      SIGRTMAX - 17, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
 TEST_F(MallocDebugTest, get_malloc_leak_info_multi) {
@@ -1226,10 +1266,7 @@
   debug_free(pointers[2]);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
-      SIGRTMAX - 17, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
 TEST_F(MallocDebugTest, get_malloc_backtrace_with_header) {
@@ -1261,10 +1298,7 @@
   initialized = false;
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
-      SIGRTMAX - 17, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
 static std::string SanitizeHeapData(const std::string& data) {
@@ -1375,9 +1409,6 @@
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
-      SIGRTMAX - 17, getpid());
-  expected_log += android::base::StringPrintf(
       "6 malloc_debug Dumping to file: /data/local/tmp/backtrace_heap.%d.txt\n\n", getpid());
   ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
 }
@@ -1649,13 +1680,7 @@
   debug_free_malloc_leak_info(info);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to enable backtracing.\n",
-      SIGRTMAX - 19, getpid());
-  expected_log += android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
-      SIGRTMAX - 17, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
 TEST_F(MallocDebugTest, backtrace_same_stack) {
@@ -1712,10 +1737,7 @@
   debug_free(pointers[3]);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
-      SIGRTMAX - 17, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
 TEST_F(MallocDebugTest, backtrace_same_stack_zygote) {
@@ -1774,10 +1796,7 @@
   debug_free(pointers[3]);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
-      SIGRTMAX - 17, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
 TEST_F(MallocDebugTest, backtrace_same_stack_mix_zygote) {
@@ -1844,10 +1863,7 @@
   debug_free(pointers[3]);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
-      SIGRTMAX - 17, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
 TEST_F(MallocDebugTest, backtrace_frame_data_nullptr_same_size) {
@@ -1891,10 +1907,7 @@
   debug_free(pointers[3]);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
-      SIGRTMAX - 17, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
 TEST_F(MallocDebugTest, overflow) {
@@ -2022,10 +2035,7 @@
   debug_free(pointer);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
-      SIGRTMAX - 17, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
 TEST_F(MallocDebugTest, max_size) {
@@ -2193,10 +2203,7 @@
   ASSERT_STREQ(expected.c_str(), actual.c_str());
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the allocation records.\n",
-      SIGRTMAX - 18, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 
   debug_free(pointer);
 }
@@ -2251,10 +2258,7 @@
   ASSERT_STREQ(expected.c_str(), actual.c_str());
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the allocation records.\n",
-      SIGRTMAX - 18, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 
   debug_free(pointer);
 }
@@ -2293,10 +2297,7 @@
   ASSERT_STREQ(expected.c_str(), actual.c_str());
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the allocation records.\n",
-      SIGRTMAX - 18, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 
   debug_free(pointer);
 }
@@ -2348,9 +2349,6 @@
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the allocation records.\n",
-      SIGRTMAX - 18, getpid());
-  expected_log += android::base::StringPrintf(
       "6 malloc_debug Cannot create record alloc file %s: Too many symbolic links encountered\n",
       RECORD_ALLOCS_FILE);
   ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
diff --git a/libc/private/bionic_lock.h b/libc/private/bionic_lock.h
index 410e637..ec179d1 100644
--- a/libc/private/bionic_lock.h
+++ b/libc/private/bionic_lock.h
@@ -70,8 +70,9 @@
   }
 
   void unlock() {
+    bool shared = process_shared; /* cache to local variable */
     if (atomic_exchange_explicit(&state, Unlocked, memory_order_release) == LockedWithWaiter) {
-      __futex_wake_ex(&state, process_shared, 1);
+      __futex_wake_ex(&state, shared, 1);
     }
   }
 };
diff --git a/libc/symbol_ordering b/libc/symbol_ordering
index 6fcc09e..10245db 100644
--- a/libc/symbol_ordering
+++ b/libc/symbol_ordering
@@ -3,200 +3,209 @@
 # symbols by size, we usually have less dirty pages at runtime, because small
 # symbols are grouped together.
 
-_ZZ17__find_icu_symbolPKcE9found_icu
-_ZL24gHeapprofdInitInProgress
-_ZL27gHeapprofdInitHookInstalled
+ctl_initialized
+gGlobalsMutating
+global_hashtable_initialized
+gmtcheck.gmt_is_set
+had_conf_error
+je_background_thread_enabled_state
+je_log_init_done
 je_opt_abort
 je_opt_abort_conf
+je_opt_background_thread
 je_opt_junk_alloc
 je_opt_junk_free
+je_opt_stats_print
 je_opt_utrace
 je_opt_xmalloc
 je_opt_zero
+je_tsd_booted
 malloc_disabled_tcache
-had_conf_error
 malloc_slow_flags
-je_opt_background_thread
-ctl_initialized
-je_log_init_done
 mmap_flags
 os_overcommits
-je_opt_stats_print
-je_tsd_booted
-global_hashtable_initialized
-gmtcheck.gmt_is_set
 restartloop
-_ZZ12bindresvportE4port
-ru_counter
+_ZL24gHeapprofdInitInProgress
+_ZL27gHeapprofdInitHookInstalled
+_ZL29gMallocZygoteChildProfileable
+_ZZ17__find_icu_symbolPKcE9found_icu
 ru_a
-ru_x
 ru_b
-ru_seed
+ru_counter
 ru_g
-ru_seed2
 ru_msb
-je_narenas_auto
-je_ncpus
-je_init_system_thp_mode
-je_nhbins
-je_tsd_tsd
-optreset
-_rs_forked
-daylight
-gMallocLeakZygoteChild
-_ZL18netdClientInitOnce
-je_opt_narenas
-narenas_total
-je_malloc_disable.once_control
-je_opt_metadata_thp
-je_opt_thp
-stack_nelms
-tcaches_past
-ncleanups
-error_message_count
-error_one_per_line
-_ZZ13error_at_lineE9last_line
-_ZL13g_locale_once
-_ZL30g_propservice_protocol_version
-_res_cache_once
-_res_key
-_rs_forkdetect._rs_pid
-ru_pid
-lcl_is_set
-__cxa_finalize.call_depth
-seed48.sseed
-ether_aton.addr
-je_background_thread_info
-je_malloc_message
-je_tcache_bin_info
-je_tcache_maxclass
-je_tcaches
-optarg
-suboptarg
-timezone
-_ZGVZ17__find_icu_symbolPKcE9found_icu
-_ZL17g_libicuuc_handle
-__malloc_hook
-__realloc_hook
-__free_hook
-__memalign_hook
-je_malloc_conf
-malloc_initializer
+ru_seed
+ru_seed2
+ru_x
+_ZZ12bindresvportE4port
 a0
-je_opt_dirty_decay_ms
-je_opt_muzzy_decay_ms
-dirty_decay_ms_default.0
-muzzy_decay_ms_default.0
+__atexit
+atexit_mutex
 b0
 ctl_arenas
 ctl_stats
-je_hooks_arena_new_hook
-os_page
-tcaches_avail
-_ZN9prop_area8pa_size_E
-_ZN9prop_area13pa_data_size_E
-_ZL6g_lock
-_ZL6g_tags
-_ZZ8c16rtombE15__private_state
-_ZZ8c32rtombE15__private_state
+__cxa_finalize.call_depth
+daylight
+dirty_decay_ms_default.0
 environ
+error_message_count
+error_one_per_line
 error_print_progname
-_ZZ13error_at_lineE9last_file
-_ZZ14__icu_charTypejE10u_charType
-_ZGVZ14__icu_charTypejE10u_charType
-_ZZ25__icu_getIntPropertyValuej9UPropertyE21u_getIntPropertyValue
-_ZGVZ25__icu_getIntPropertyValuej9UPropertyE21u_getIntPropertyValue
-_ZZ23__icu_hasBinaryPropertyj9UPropertyPFiiEE19u_hasBinaryProperty
-_ZGVZ23__icu_hasBinaryPropertyj9UPropertyPFiiEE19u_hasBinaryProperty
-__progname
-_ZZ8mbrtoc16E15__private_state
-_ZZ8mbrtoc32E15__private_state
-_ZL14syslog_log_tag
-__system_property_area__
-_ZZ7mbrtowcE15__private_state
-_ZZ10mbsnrtowcsE15__private_state
-_ZZ7wcrtombE15__private_state
-_ZZ10wcsnrtombsE15__private_state
-_ZZ8iswcntrlE10u_charType
-_ZGVZ8iswcntrlE10u_charType
-_ZZ8iswdigitE9u_isdigit
-_ZGVZ8iswdigitE9u_isdigit
-_ZZ8iswpunctE9u_ispunct
-_ZGVZ8iswpunctE9u_ispunct
-_ZZ8towlowerE9u_tolower
-_ZGVZ8towlowerE9u_tolower
-_ZZ8towupperE9u_toupper
-_ZGVZ8towupperE9u_toupper
+__free_hook
+g_atexit_lock
+gGlobalsMutateLock
 global_hashtable
+gMallocLeakZygoteChild
+gmtptr
 handlers
-p5s
-ut
-rs
-rsx
+je_background_thread_info
+je_hooks_arena_new_hook
+je_init_system_thp_mode
+je_malloc_conf
+je_malloc_disable.once_control
+je_malloc_message
+je_narenas_auto
+je_ncpus
+je_nhbins
+je_opt_dirty_decay_ms
+je_opt_metadata_thp
+je_opt_muzzy_decay_ms
+je_opt_narenas
+je_opt_thp
+je_tcache_bin_info
+je_tcache_maxclass
+je_tcaches
+je_tsd_tsd
+lastenv
+lcl_is_set
+lclptr
+locallock
+malloc_disabled_lock
+__malloc_hook
+malloc_initializer
 mbrlen.mbs
 mbtowc.mbs
-wctomb.mbs
-ru_reseed
+__memalign_hook
+muzzy_decay_ms_default.0
+narenas_total
+ncleanups
+optarg
+optreset
+os_page
+p5s
+__progname
+random_mutex
+__realloc_hook
+_res_cache_list_lock
+_res_cache_once
+_res_key
+__res_randomid.__libc_mutex_random
+rs
+_rs_forkdetect._rs_pid
+_rs_forked
+rsx
+ru_pid
 ru_prf
-tmpnam.tmpcount
-lastenv
-strtok.last
+ru_reseed
 __stack_chk_guard
-lclptr
-gmtptr
-_ZGVZ14tzset_unlockedE20persist_sys_timezone
+stack_nelms
+strtok.last
+suboptarg
+__system_property_area__
+tcaches_avail
+tcaches_past
+timezone
+tmpnam.tmpcount
+ut
+wctomb.mbs
+_ZL11g_arc4_lock
+_ZL13g_locale_once
 _ZL13g_thread_list
-__atexit
+_ZL14syslog_log_tag
+_ZL16gHeapprofdHandle
+_ZL17g_libicuuc_handle
+_ZL18netdClientInitOnce
+_ZL30g_propservice_protocol_version
+_ZN9prop_area13pa_data_size_E
+_ZN9prop_area8pa_size_E
+_ZZ10mbsnrtowcsE15__private_state
+_ZZ10wcsnrtombsE15__private_state
+_ZZ13error_at_lineE9last_file
+_ZZ13error_at_lineE9last_line
+_ZZ14__icu_charTypejE10u_charType
+_ZZ23__bionic_get_shell_pathE7sh_path
+_ZZ23__icu_hasBinaryPropertyj9UPropertyPFiiEE19u_hasBinaryProperty
+_ZZ25__icu_getIntPropertyValuej9UPropertyE21u_getIntPropertyValue
+_ZZ7mbrtowcE15__private_state
+_ZZ7wcrtombE15__private_state
+_ZZ8c16rtombE15__private_state
+_ZZ8c32rtombE15__private_state
+_ZZ8iswcntrlE10u_charType
+_ZZ8iswdigitE9u_isdigit
+_ZZ8iswpunctE9u_ispunct
+_ZZ8mbrtoc16E15__private_state
+_ZZ8mbrtoc32E15__private_state
+_ZZ8towlowerE9u_tolower
+_ZZ8towupperE9u_toupper
+ether_aton.addr
+seed48.sseed
+__dtoa_locks
+_ZGVZ14__icu_charTypejE10u_charType
+_ZGVZ14tzset_unlockedE20persist_sys_timezone
+_ZGVZ17__find_icu_symbolPKcE9found_icu
+_ZGVZ23__bionic_get_shell_pathE7sh_path
+_ZGVZ23__icu_hasBinaryPropertyj9UPropertyPFiiEE19u_hasBinaryProperty
+_ZGVZ25__icu_getIntPropertyValuej9UPropertyE21u_getIntPropertyValue
+_ZGVZ8iswcntrlE10u_charType
+_ZGVZ8iswdigitE9u_isdigit
+_ZGVZ8iswpunctE9u_ispunct
+_ZGVZ8towlowerE9u_tolower
+_ZGVZ8towupperE9u_toupper
+_ZL10gAllocated
+_ZL11gAllocLimit
+_ZL13g_atfork_list
+_ZL6g_lock
+_ZL6g_tags
 je_opt_stats_print_opts
 nuls
 precsize_ntoa.retbuf
 __p_secstodate.output
-_ZL13g_atfork_list
-inet_ntoa.b
 ether_ntoa.buf
-__sym_ntos.unname
-__sym_ntop.unname
-__p_type.typebuf
+inet_ntoa.b
 __p_class.classbuf
-malloc_disabled_lock
-_ZL11g_arc4_lock
-_res_cache_list_lock
+__p_type.typebuf
+__sym_ntop.unname
+__sym_ntos.unname
+_ZL10gFunctions
+_ZL12vendor_group
+_ZL13vendor_passwd
+freelist
 __p_option.nbuf
 __p_time.nbuf
-atexit_mutex
-random_mutex
-__res_randomid.__libc_mutex_random
-locallock
-g_atexit_lock
-_ZL10gFunctions
-_ZL13vendor_passwd
-_ZL12vendor_group
-tm
 _ZL18g_thread_list_lock
-buf_asctime
-__dtoa_locks
-freelist
-__loc_ntoa.tmpbuf
+tm
 _ZL8g_locale
+ctl_mtx
+init_lock
 je_arenas_lock
 je_background_thread_lock
-init_lock
-ctl_mtx
 tcaches_mtx
 je_tsd_init_head
+buf_asctime
+__loc_ntoa.tmpbuf
+utmp
 _ZZ14tzset_unlockedE20persist_sys_timezone
 arena_binind_div_info
 __hexdig_D2A
 lcl_TZname
-utmp
 inet_nsap_ntoa_tmpbuf
-_ZL17system_properties
 _ZL7key_map
+_ZL17system_properties
 private_mem
+_res_cache_list
 __libc_globals
 tmpnam.buf
-_res_cache_list
-_nres
-je_extent_mutex_pool
-je_arenas
 je_extents_rtree
+_nres
+je_arenas
+je_extent_mutex_pool
diff --git a/linker/linker.cpp b/linker/linker.cpp
index c60ab6a..d62eaec 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -2383,9 +2383,26 @@
 
   if (sym != nullptr) {
     uint32_t bind = ELF_ST_BIND(sym->st_info);
+    uint32_t type = ELF_ST_TYPE(sym->st_info);
 
     if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
-      *symbol = reinterpret_cast<void*>(found->resolve_symbol_address(sym));
+      if (type == STT_TLS) {
+        // For a TLS symbol, dlsym returns the address of the current thread's
+        // copy of the symbol. This function may allocate a DTV and/or storage
+        // for the source TLS module. (Allocating a DTV isn't necessary if the
+        // symbol is part of static TLS, but it's simpler to reuse
+        // __tls_get_addr.)
+        soinfo_tls* tls_module = found->get_tls();
+        if (tls_module == nullptr) {
+          DL_ERR("TLS symbol \"%s\" in solib \"%s\" with no TLS segment",
+                 sym_name, found->get_realpath());
+          return false;
+        }
+        const TlsIndex ti { tls_module->module_id, sym->st_value };
+        *symbol = TLS_GET_ADDR(&ti);
+      } else {
+        *symbol = reinterpret_cast<void*>(found->resolve_symbol_address(sym));
+      }
       failure_guard.Disable();
       LD_LOG(kLogDlsym,
              "... dlsym successful: sym_name=\"%s\", sym_ver=\"%s\", found in=\"%s\", address=%p",
@@ -3987,7 +4004,7 @@
   /* Handle serializing/sharing the RELRO segment */
   if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
     if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
-                                       extinfo->relro_fd) < 0) {
+                                       extinfo->relro_fd, relro_fd_offset) < 0) {
       DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
              get_realpath(), strerror(errno));
       return false;
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 1aaa17f..3534287 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -831,16 +831,17 @@
  *   phdr_count  -> number of entries in tables
  *   load_bias   -> load bias
  *   fd          -> writable file descriptor to use
+ *   file_offset -> pointer to offset into file descriptor to use/update
  * Return:
  *   0 on error, -1 on failure (error code in errno).
  */
 int phdr_table_serialize_gnu_relro(const ElfW(Phdr)* phdr_table,
                                    size_t phdr_count,
                                    ElfW(Addr) load_bias,
-                                   int fd) {
+                                   int fd,
+                                   size_t* file_offset) {
   const ElfW(Phdr)* phdr = phdr_table;
   const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
-  ssize_t file_offset = 0;
 
   for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
     if (phdr->p_type != PT_GNU_RELRO) {
@@ -856,11 +857,11 @@
       return -1;
     }
     void* map = mmap(reinterpret_cast<void*>(seg_page_start), size, PROT_READ,
-                     MAP_PRIVATE|MAP_FIXED, fd, file_offset);
+                     MAP_PRIVATE|MAP_FIXED, fd, *file_offset);
     if (map == MAP_FAILED) {
       return -1;
     }
-    file_offset += size;
+    *file_offset += size;
   }
   return 0;
 }
diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h
index 9761bc8..5d1cfc2 100644
--- a/linker/linker_phdr.h
+++ b/linker/linker_phdr.h
@@ -119,7 +119,7 @@
                                  ElfW(Addr) load_bias);
 
 int phdr_table_serialize_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count,
-                                   ElfW(Addr) load_bias, int fd);
+                                   ElfW(Addr) load_bias, int fd, size_t* file_offset);
 
 int phdr_table_map_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count,
                              ElfW(Addr) load_bias, int fd, size_t* file_offset);
diff --git a/linker/linker_soinfo.cpp b/linker/linker_soinfo.cpp
index 89119aa..31ee74c 100644
--- a/linker/linker_soinfo.cpp
+++ b/linker/linker_soinfo.cpp
@@ -297,7 +297,11 @@
 }
 
 static bool symbol_matches_soaddr(const ElfW(Sym)* sym, ElfW(Addr) soaddr) {
+  // Skip TLS symbols. A TLS symbol's value is relative to the start of the TLS segment rather than
+  // to the start of the solib. The solib only reserves space for the initialized part of the TLS
+  // segment. (i.e. .tdata is followed by .tbss, and .tbss overlaps other sections.)
   return sym->st_shndx != SHN_UNDEF &&
+      ELF_ST_TYPE(sym->st_info) != STT_TLS &&
       soaddr >= sym->st_value &&
       soaddr < sym->st_value + sym->st_size;
 }
diff --git a/tests/Android.bp b/tests/Android.bp
index d1625d2..71cf8a6 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -426,6 +426,11 @@
 cc_defaults {
     name: "bionic_unit_tests_defaults",
     host_supported: false,
+    gtest: false,
+
+    defaults: [
+        "bionic_tests_defaults",
+    ],
 
     whole_static_libs: [
         "libBionicTests",
@@ -437,12 +442,14 @@
         "libtinyxml2",
         "liblog",
         "libbase",
+        "libgtest_isolated",
     ],
 
     srcs: [
         // TODO: Include __cxa_thread_atexit_test.cpp to glibc tests once it is upgraded (glibc 2.18+)
         "__cxa_thread_atexit_test.cpp",
         "gtest_globals.cpp",
+        "gtest_main.cpp",
         "thread_local_test.cpp",
     ],
 
@@ -461,6 +468,7 @@
         android: {
             shared_libs: [
                 "ld-android",
+                "libandroidicu",
                 "libdl",
                 "libdl_android",
                 "libdl_preempt_test_1",
@@ -489,29 +497,6 @@
             ],
         },
     },
-}
-
-cc_test {
-    name: "bionic-unit-tests",
-    gtest: false,
-    defaults: [
-        "bionic_unit_tests_defaults",
-        "bionic_tests_defaults",
-    ],
-
-    srcs: [
-        "gtest_main.cpp",
-    ],
-
-    static_libs: [
-        "libgtest_isolated",
-    ],
-
-    target: {
-        android: {
-            shared_libs: ["libandroidicu"],
-        },
-    },
 
     required: [
         "cfi_test_helper",
@@ -656,6 +641,24 @@
     ],
 }
 
+cc_test {
+    name: "bionic-unit-tests",
+    defaults: [
+        "bionic_unit_tests_defaults",
+    ],
+}
+
+cc_test {
+    name: "bionic-unit-tests-scudo",
+    defaults: [
+        "bionic_unit_tests_defaults",
+    ],
+
+    shared_libs: [
+        "libc_scudo",
+    ],
+}
+
 // -----------------------------------------------------------------------------
 // Tests for the device linked against bionic's static library. Run with:
 //   adb shell /data/nativetest/bionic-unit-tests-static/bionic-unit-tests-static
@@ -698,10 +701,6 @@
 
     static_executable: true,
     stl: "libc++_static",
-
-    // libclang_rt.builtins does not work with libm
-    // http://b/117167374
-    no_libcrt: true,
 }
 
 // -----------------------------------------------------------------------------
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index 1bc5030..3af52d4 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -450,7 +450,21 @@
         fprintf(stderr, "in child: %s\n", dlerror());
         exit(1);
       }
-      exit(0);
+      fn f = reinterpret_cast<fn>(dlsym(handle, "getRandomNumber"));
+      ASSERT_DL_NOTNULL(f);
+      EXPECT_EQ(4, f());
+
+      if (recursive) {
+        fn f = reinterpret_cast<fn>(dlsym(handle, "getBiggerRandomNumber"));
+        ASSERT_DL_NOTNULL(f);
+        EXPECT_EQ(8, f());
+      }
+
+      uint32_t* taxicab_number =
+              reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number"));
+      ASSERT_DL_NOTNULL(taxicab_number);
+      EXPECT_EQ(1729U, *taxicab_number);
+      exit(testing::Test::HasFailure());
     }
 
     // continuing in parent
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index f3be988..c6d7ddb 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -982,16 +982,16 @@
 }
 
 #if defined (__aarch64__)
-#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/arm64/"
+#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib64/arm64/"
 #elif defined (__arm__)
 #define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/arm/"
 #elif defined (__i386__)
 #define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/x86/"
 #elif defined (__x86_64__)
-#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/x86_64/"
+#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib64/x86_64/"
 #elif defined (__mips__)
 #if defined(__LP64__)
-#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/mips64/"
+#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib64/mips64/"
 #else
 #define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/mips/"
 #endif
diff --git a/tests/elftls_dl_test.cpp b/tests/elftls_dl_test.cpp
index 88225d8..6d88880 100644
--- a/tests/elftls_dl_test.cpp
+++ b/tests/elftls_dl_test.cpp
@@ -269,3 +269,69 @@
   GTEST_SKIP() << "test doesn't apply to glibc";
 #endif
 }
+
+// Use dlsym to get the address of a TLS variable in static TLS and compare it
+// against the ordinary address of the variable.
+TEST(elftls_dl, dlsym_static_tls) {
+  void* lib = dlopen("libtest_elftls_shared_var.so", RTLD_LOCAL | RTLD_NOW);
+  ASSERT_NE(nullptr, lib);
+
+  int* var_addr = static_cast<int*>(dlsym(lib, "elftls_shared_var"));
+  ASSERT_EQ(&elftls_shared_var, var_addr);
+
+  std::thread([lib] {
+    int* var_addr = static_cast<int*>(dlsym(lib, "elftls_shared_var"));
+    ASSERT_EQ(&elftls_shared_var, var_addr);
+  }).join();
+}
+
+// Use dlsym to get the address of a TLS variable in dynamic TLS and compare it
+// against the ordinary address of the variable.
+TEST(elftls_dl, dlsym_dynamic_tls) {
+  void* lib = dlopen("libtest_elftls_dynamic.so", RTLD_LOCAL | RTLD_NOW);
+  ASSERT_NE(nullptr, lib);
+  auto get_var_addr = reinterpret_cast<int*(*)()>(dlsym(lib, "get_large_tls_var_addr"));
+  ASSERT_NE(nullptr, get_var_addr);
+
+  int* var_addr = static_cast<int*>(dlsym(lib, "large_tls_var"));
+  ASSERT_EQ(get_var_addr(), var_addr);
+
+  std::thread([lib, get_var_addr] {
+    int* var_addr = static_cast<int*>(dlsym(lib, "large_tls_var"));
+    ASSERT_EQ(get_var_addr(), var_addr);
+  }).join();
+}
+
+// Calling dladdr on a TLS variable's address doesn't find anything.
+TEST(elftls_dl, dladdr_on_tls_var) {
+  Dl_info info;
+
+  // Static TLS variable
+  ASSERT_EQ(0, dladdr(&elftls_shared_var, &info));
+
+  // Dynamic TLS variable
+  void* lib = dlopen("libtest_elftls_dynamic.so", RTLD_LOCAL | RTLD_NOW);
+  ASSERT_NE(nullptr, lib);
+  int* var_addr = static_cast<int*>(dlsym(lib, "large_tls_var"));
+  ASSERT_EQ(0, dladdr(var_addr, &info));
+}
+
+// Verify that dladdr does not misinterpret a TLS symbol's value as a virtual
+// address.
+TEST(elftls_dl, dladdr_skip_tls_symbol) {
+  void* lib = dlopen("libtest_elftls_dynamic.so", RTLD_LOCAL | RTLD_NOW);
+
+  auto get_local_addr = reinterpret_cast<void*(*)()>(dlsym(lib, "get_local_addr"));
+  ASSERT_NE(nullptr, get_local_addr);
+  void* local_addr = get_local_addr();
+
+  Dl_info info;
+  ASSERT_NE(0, dladdr(local_addr, &info));
+
+  std::string libpath = GetTestlibRoot() + "/libtest_elftls_dynamic.so";
+  char dli_realpath[PATH_MAX];
+  ASSERT_TRUE(realpath(info.dli_fname, dli_realpath));
+  ASSERT_STREQ(libpath.c_str(), dli_realpath);
+  ASSERT_STREQ(nullptr, info.dli_sname);
+  ASSERT_EQ(nullptr, info.dli_saddr);
+}
diff --git a/tests/libs/elftls_dynamic.cpp b/tests/libs/elftls_dynamic.cpp
index 7fa239c..6da2f6f 100644
--- a/tests/libs/elftls_dynamic.cpp
+++ b/tests/libs/elftls_dynamic.cpp
@@ -27,6 +27,24 @@
  */
 
 // This shared object test library is dlopen'ed by the main test executable.
+
+// Export a large TLS variable from a solib for testing dladdr and dlsym. The
+// TLS symbol's value will appear to overlap almost everything else in the
+// shared object, but dladdr must not return it.
+__thread char large_tls_var[4 * 1024 * 1024];
+
+extern "C" char* get_large_tls_var_addr() {
+  return large_tls_var;
+}
+
+// For testing dladdr, return an address that's part of the solib's .bss
+// section, but does not have an entry in the dynsym table and whose
+// solib-relative address appears to overlap with the large TLS variable.
+extern "C" void* get_local_addr() {
+  static char dummy[1024];
+  return &dummy[512];
+}
+
 // This variable comes from libtest_elftls_shared_var.so, which is part of
 // static TLS. Verify that a GD-model access can access the variable.
 //