Merge "Update doc comment about running the benchmarks."
diff --git a/libc/Android.bp b/libc/Android.bp
index d8a1d70..931f87b 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -762,12 +762,13 @@
                 "arch-arm/generic/bionic/strlen.c",
 
                 "arch-arm/bionic/__aeabi_read_tp.S",
-                "arch-arm/bionic/atomics_arm.c",
                 "arch-arm/bionic/__bionic_clone.S",
+                "arch-arm/bionic/__restore.S",
                 "arch-arm/bionic/_exit_with_stack_teardown.S",
+                "arch-arm/bionic/atomics_arm.c",
+                "arch-arm/bionic/bpabi.c",
                 "arch-arm/bionic/libcrt_compat.c",
                 "arch-arm/bionic/popcount_tab.c",
-                "arch-arm/bionic/__restore.S",
                 "arch-arm/bionic/setjmp.S",
                 "arch-arm/bionic/syscall.S",
                 "arch-arm/bionic/vfork.S",
@@ -1461,12 +1462,7 @@
             srcs: ["arch-x86/dynamic_function_dispatch.cpp"],
         },
         arm: {
-            srcs: [
-                "arch-arm/dynamic_function_dispatch.cpp",
-
-                // Workaround for b/120254692.
-                "arch-arm/dynamic_function_wrapper.S",
-            ],
+            srcs: ["arch-arm/dynamic_function_dispatch.cpp"],
         },
     },
 
diff --git a/libc/arch-arm/dynamic_function_wrapper.S b/libc/arch-arm/bionic/bpabi.c
similarity index 68%
rename from libc/arch-arm/dynamic_function_wrapper.S
rename to libc/arch-arm/bionic/bpabi.c
index 1d2842b..5c9cd99 100644
--- a/libc/arch-arm/dynamic_function_wrapper.S
+++ b/libc/arch-arm/bionic/bpabi.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,12 +26,18 @@
  * SUCH DAMAGE.
  */
 
-#include <private/bionic_asm.h>
+extern long long __divdi3(long long, long long);
+extern unsigned long long __udivdi3(unsigned long long, unsigned long long);
 
-#define FUNCTION_DELEGATE(name, impl) \
-ENTRY(name); \
-    b impl; \
-END(name)
+long long __gnu_ldivmod_helper(long long a, long long b, long long* remainder) {
+  long long quotient = __divdi3(a, b);
+  *remainder = a - b * quotient;
+  return quotient;
+}
 
-FUNCTION_DELEGATE(strcmp, strcmp_internal)
-FUNCTION_DELEGATE(strlen, strlen_internal)
+unsigned long long __gnu_uldivmod_helper(unsigned long long a, unsigned long long b,
+                                         unsigned long long* remainder) {
+  unsigned long long quotient = __udivdi3(a, b);
+  *remainder = a - b * quotient;
+  return quotient;
+}
diff --git a/libc/arch-arm/dynamic_function_dispatch.cpp b/libc/arch-arm/dynamic_function_dispatch.cpp
index 09fd8f3..640f330 100644
--- a/libc/arch-arm/dynamic_function_dispatch.cpp
+++ b/libc/arch-arm/dynamic_function_dispatch.cpp
@@ -89,15 +89,11 @@
     return r0;
 }
 
-#define DEFINE_IFUNC_WITH_SUFFIX(name, suffix) \
-    name##_func name##suffix __attribute__((ifunc(#name "_resolver"))); \
+#define DEFINE_IFUNC(name) \
+    name##_func name __attribute__((ifunc(#name "_resolver"))); \
     __attribute__((visibility("hidden"))) \
     name##_func* name##_resolver()
 
-#define DEFINE_IFUNC(name) DEFINE_IFUNC_WITH_SUFFIX(name, )
-
-#define DEFINE_INTERNAL_IFUNC(name) DEFINE_IFUNC_WITH_SUFFIX(name, _internal)
-
 #define DECLARE_FUNC(type, name) \
     __attribute__((visibility("hidden"))) \
     type name
@@ -291,7 +287,7 @@
 }
 
 typedef int strcmp_func(const char* __lhs, const char* __rhs);
-DEFINE_INTERNAL_IFUNC(strcmp) {
+DEFINE_IFUNC(strcmp) {
     switch(get_cpu_variant()) {
         case kCortexA9:
             RETURN_FUNC(strcmp_func, strcmp_a9);
@@ -305,7 +301,7 @@
 }
 
 typedef size_t strlen_func(const char* __s);
-DEFINE_INTERNAL_IFUNC(strlen) {
+DEFINE_IFUNC(strlen) {
     switch(get_cpu_variant()) {
         case kCortexA9:
             RETURN_FUNC(strlen_func, strlen_a9);
diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
index e9f9db2..9dc4d12 100644
--- a/libc/bionic/malloc_common.cpp
+++ b/libc/bionic/malloc_common.cpp
@@ -32,14 +32,7 @@
 // calls and add special debugging code to attempt to catch allocation
 // errors. All of the debugging code is implemented in a separate shared
 // library that is only loaded when the property "libc.debug.malloc.options"
-// is set to a non-zero value. There are two functions exported to
-// allow ddms, or other external users to get information from the debug
-// allocation.
-//   get_malloc_leak_info: Returns information about all of the known native
-//                         allocations that are currently in use.
-//   free_malloc_leak_info: Frees the data allocated by the call to
-//                          get_malloc_leak_info.
-//   write_malloc_leak_info: Writes the leak info data to a file.
+// is set to a non-zero value.
 
 #include <errno.h>
 #include <stdint.h>
diff --git a/libc/bionic/malloc_common_dynamic.cpp b/libc/bionic/malloc_common_dynamic.cpp
index 64f9f6f..599ac6a 100644
--- a/libc/bionic/malloc_common_dynamic.cpp
+++ b/libc/bionic/malloc_common_dynamic.cpp
@@ -409,39 +409,29 @@
 // =============================================================================
 // Functions to support dumping of native heap allocations using malloc debug.
 // =============================================================================
-
-// Retrieve native heap information.
-//
-// "*info" is set to a buffer we allocate
-// "*overall_size" is set to the size of the "info" buffer
-// "*info_size" is set to the size of a single entry
-// "*total_memory" is set to the sum of all allocations we're tracking; does
-//   not include heap overhead
-// "*backtrace_size" is set to the maximum number of entries in the back trace
-extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overall_size,
-    size_t* info_size, size_t* total_memory, size_t* backtrace_size) {
+bool GetMallocLeakInfo(android_mallopt_leak_info_t* leak_info) {
   void* func = gFunctions[FUNC_GET_MALLOC_LEAK_INFO];
   if (func == nullptr) {
-    return;
+    errno = ENOTSUP;
+    return false;
   }
-  reinterpret_cast<get_malloc_leak_info_func_t>(func)(info, overall_size, info_size, total_memory,
-                                                      backtrace_size);
+  reinterpret_cast<get_malloc_leak_info_func_t>(func)(
+      &leak_info->buffer, &leak_info->overall_size, &leak_info->info_size,
+      &leak_info->total_memory, &leak_info->backtrace_size);
+  return true;
 }
 
-extern "C" void free_malloc_leak_info(uint8_t* info) {
+bool FreeMallocLeakInfo(android_mallopt_leak_info_t* leak_info) {
   void* func = gFunctions[FUNC_FREE_MALLOC_LEAK_INFO];
   if (func == nullptr) {
-    return;
+    errno = ENOTSUP;
+    return false;
   }
-  reinterpret_cast<free_malloc_leak_info_func_t>(func)(info);
+  reinterpret_cast<free_malloc_leak_info_func_t>(func)(leak_info->buffer);
+  return true;
 }
 
-extern "C" void write_malloc_leak_info(FILE* fp) {
-  if (fp == nullptr) {
-    error_log("write_malloc_leak_info called with a nullptr");
-    return;
-  }
-
+bool WriteMallocLeakInfo(FILE* fp) {
   void* func = gFunctions[FUNC_WRITE_LEAK_INFO];
   bool written = false;
   if (func != nullptr) {
@@ -453,7 +443,9 @@
     fprintf(fp, "# adb shell stop\n");
     fprintf(fp, "# adb shell setprop libc.debug.malloc.options backtrace\n");
     fprintf(fp, "# adb shell start\n");
+    errno = ENOTSUP;
   }
+  return written;
 }
 // =============================================================================
 
@@ -484,6 +476,27 @@
   if (opcode == M_SET_ALLOCATION_LIMIT_BYTES) {
     return LimitEnable(arg, arg_size);
   }
+  if (opcode == M_WRITE_MALLOC_LEAK_INFO_TO_FILE) {
+    if (arg == nullptr || arg_size != sizeof(FILE*)) {
+      errno = EINVAL;
+      return false;
+    }
+    return WriteMallocLeakInfo(reinterpret_cast<FILE*>(arg));
+  }
+  if (opcode == M_GET_MALLOC_LEAK_INFO) {
+    if (arg == nullptr || arg_size != sizeof(android_mallopt_leak_info_t)) {
+      errno = EINVAL;
+      return false;
+    }
+    return GetMallocLeakInfo(reinterpret_cast<android_mallopt_leak_info_t*>(arg));
+  }
+  if (opcode == M_FREE_MALLOC_LEAK_INFO) {
+    if (arg == nullptr || arg_size != sizeof(android_mallopt_leak_info_t)) {
+      errno = EINVAL;
+      return false;
+    }
+    return FreeMallocLeakInfo(reinterpret_cast<android_mallopt_leak_info_t*>(arg));
+  }
   return HeapprofdMallopt(opcode, arg, arg_size);
 }
 // =============================================================================
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 55ca9dc..f0fccf5 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1473,15 +1473,10 @@
     malloc_enable; # apex
     malloc_iterate; # apex
 
-    # Used by libmediautils
-    write_malloc_leak_info; # apex
-    free_malloc_leak_info; # apex
-    get_malloc_leak_info; # apex
-
     # Used by libandroid_net
     android_getaddrinfofornet; # apex
 
-    # Used by libandroid_runtime and libmedia
+    # Used by libandroid_runtime, libmedia and libmediautils
     android_mallopt; # apex
 } LIBC_P;
 
diff --git a/libc/malloc_hooks/tests/malloc_hooks_tests.cpp b/libc/malloc_hooks/tests/malloc_hooks_tests.cpp
index 0d23a6a..86e20ea 100644
--- a/libc/malloc_hooks/tests/malloc_hooks_tests.cpp
+++ b/libc/malloc_hooks/tests/malloc_hooks_tests.cpp
@@ -38,6 +38,7 @@
 
 #include <gtest/gtest.h>
 
+#include <private/bionic_malloc.h>
 #include <private/bionic_malloc_dispatch.h>
 #include <tests/utils.h>
 
@@ -197,19 +198,15 @@
 }
 
 TEST_F(MallocHooksTest, DISABLED_extended_functions) {
-  uint8_t* info = nullptr;
-  size_t overall_size = 100;
-  size_t info_size = 200;
-  size_t total_memory = 300;
-  size_t backtrace_size = 400;
-  get_malloc_leak_info(&info, &overall_size, &info_size, &total_memory, &backtrace_size);
-  EXPECT_EQ(nullptr, info);
-  EXPECT_EQ(0U, overall_size);
-  EXPECT_EQ(0U, info_size);
-  EXPECT_EQ(0U, total_memory);
-  EXPECT_EQ(0U, backtrace_size);
+  android_mallopt_leak_info_t leak_info;
+  ASSERT_TRUE(android_mallopt(M_GET_MALLOC_LEAK_INFO, &leak_info, sizeof(leak_info)));
+  EXPECT_EQ(nullptr, leak_info.buffer);
+  EXPECT_EQ(0U, leak_info.overall_size);
+  EXPECT_EQ(0U, leak_info.info_size);
+  EXPECT_EQ(0U, leak_info.total_memory);
+  EXPECT_EQ(0U, leak_info.backtrace_size);
 
-  free_malloc_leak_info(info);
+  ASSERT_TRUE(android_mallopt(M_FREE_MALLOC_LEAK_INFO, &leak_info, sizeof(leak_info)));
 
   malloc_enable();
   malloc_disable();
diff --git a/libc/private/bionic_malloc.h b/libc/private/bionic_malloc.h
index e8a6f6e..9c602ea 100644
--- a/libc/private/bionic_malloc.h
+++ b/libc/private/bionic_malloc.h
@@ -30,6 +30,22 @@
 
 #include <stdbool.h>
 
+// Structures for android_mallopt.
+
+typedef struct {
+  // Pointer to the buffer allocated by a call to M_GET_MALLOC_LEAK_INFO.
+  uint8_t* buffer;
+  // The size of the "info" buffer.
+  size_t overall_size;
+  // The size of a single entry.
+  size_t info_size;
+  // The sum of all allocations that have been tracked. Does not include
+  // any heap overhead.
+  size_t total_memory;
+  // The maximum number of backtrace entries.
+  size_t backtrace_size;
+} android_mallopt_leak_info_t;
+
 // Opcodes for android_mallopt.
 
 enum {
@@ -48,6 +64,26 @@
   // Called after the zygote forks to indicate this is a child.
   M_SET_ZYGOTE_CHILD = 4,
 #define M_SET_ZYGOTE_CHILD M_SET_ZYGOTE_CHILD
+
+  // Options to dump backtraces of allocations. These options only
+  // work when malloc debug has been enabled.
+
+  // Writes the backtrace information of all current allocations to a file.
+  // NOTE: arg_size has to be sizeof(FILE*) because FILE is an opaque type.
+  //   arg = FILE*
+  //   arg_size = sizeof(FILE*)
+  M_WRITE_MALLOC_LEAK_INFO_TO_FILE = 5,
+#define M_WRITE_MALLOC_LEAK_INFO_TO_FILE M_WRITE_MALLOC_LEAK_INFO_TO_FILE
+  // Get information about the backtraces of all
+  //   arg = android_mallopt_leak_info_t*
+  //   arg_size = sizeof(android_mallopt_leak_info_t)
+  M_GET_MALLOC_LEAK_INFO = 6,
+#define M_GET_MALLOC_LEAK_INFO M_GET_MALLOC_LEAK_INFO
+  // Free the memory allocated and returned by M_GET_MALLOC_LEAK_INFO.
+  //   arg = android_mallopt_leak_info_t*
+  //   arg_size = sizeof(android_mallopt_leak_info_t)
+  M_FREE_MALLOC_LEAK_INFO = 7,
+#define M_FREE_MALLOC_LEAK_INFO M_FREE_MALLOC_LEAK_INFO
 };
 
 // Manipulates bionic-specific handling of memory allocation APIs such as
diff --git a/libdl/libdl_static.cpp b/libdl/libdl_static.cpp
index 7146762..0a36e6f 100644
--- a/libdl/libdl_static.cpp
+++ b/libdl/libdl_static.cpp
@@ -23,7 +23,7 @@
 }
 
 char* dlerror() {
-  return nullptr;
+  return const_cast<char*>("libdl.a is a stub --- use libdl.so instead");
 }
 
 void* dlsym(void* /*handle*/, const char* /*symbol*/) {