Merge "Add DF_1_ORIGIN to SUPPORTED_DT_FLAGS_1."
diff --git a/benchmarks/spawn/Android.bp b/benchmarks/spawn/Android.bp
index 89d22e3..61e7bf6 100644
--- a/benchmarks/spawn/Android.bp
+++ b/benchmarks/spawn/Android.bp
@@ -43,6 +43,9 @@
         linux_glibc_x86: {
             enabled: false,
         },
+        linux_musl_x86: {
+            enabled: false,
+        },
     },
 }
 
@@ -103,6 +106,11 @@
                 "-Wl,--rpath,${ORIGIN}/../../lib64",
             ],
         },
+        linux_musl_x86_64: {
+            ldflags: [
+                "-Wl,--rpath,${ORIGIN}/../../lib64",
+            ],
+        },
     },
 }
 
diff --git a/libc/Android.bp b/libc/Android.bp
index f132669..7175c77 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1724,7 +1724,7 @@
                 // special for arm
                 cflags: ["-DCRT_LEGACY_WORKAROUND"],
                 // For backwards-compatibility, some arm32 builtins are exported from libc.so.
-                static_libs: ["libclang_rt.builtins-arm-android-exported"],
+                static_libs: ["libclang_rt.builtins-exported"],
             },
 
             // Arm 32 bit does not produce complete exidx unwind information
@@ -1754,7 +1754,7 @@
 
             shared: {
                 // For backwards-compatibility, some x86 builtins are exported from libc.so.
-                static_libs: ["libclang_rt.builtins-i686-android-exported"],
+                static_libs: ["libclang_rt.builtins-exported"],
             },
 
             // Leave the symbols in the shared library so that stack unwinders can produce
@@ -2615,10 +2615,6 @@
     stl: "none",
 }
 
-subdirs = [
-    "bionic/scudo",
-]
-
 // Export kernel uapi headers to be used in the musl sysroot.
 // Also include the execinfo headers for the libexecinfo and the
 // b64 headers for libb64 embedded in musl libc.
diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp
index 08fb187..121b26f 100644
--- a/libc/bionic/pthread_create.cpp
+++ b/libc/bionic/pthread_create.cpp
@@ -45,7 +45,6 @@
 #include "private/bionic_defs.h"
 #include "private/bionic_globals.h"
 #include "platform/bionic/macros.h"
-#include "platform/bionic/pac.h"
 #include "private/bionic_ssp.h"
 #include "private/bionic_systrace.h"
 #include "private/bionic_tls.h"
@@ -332,9 +331,11 @@
 extern "C" int __rt_sigprocmask(int, const sigset64_t*, sigset64_t*, size_t);
 
 __attribute__((no_sanitize("hwaddress")))
+#ifdef __aarch64__
 // This function doesn't return, but it does appear in stack traces. Avoid using return PAC in this
 // function because we may end up resetting IA, which may confuse unwinders due to mismatching keys.
-__BIONIC_DISABLE_PAUTH
+__attribute__((target("branch-protection=bti")))
+#endif
 static int __pthread_start(void* arg) {
   pthread_internal_t* thread = reinterpret_cast<pthread_internal_t*>(arg);
 
diff --git a/libc/malloc_debug/PointerData.cpp b/libc/malloc_debug/PointerData.cpp
index 90c9136..b982c0a 100644
--- a/libc/malloc_debug/PointerData.cpp
+++ b/libc/malloc_debug/PointerData.cpp
@@ -66,7 +66,8 @@
 std::unordered_map<FrameKeyType, size_t> PointerData::key_to_index_ GUARDED_BY(
     PointerData::frame_mutex_);
 std::unordered_map<size_t, FrameInfoType> PointerData::frames_ GUARDED_BY(PointerData::frame_mutex_);
-std::unordered_map<size_t, std::vector<unwindstack::LocalFrameData>> PointerData::backtraces_info_ GUARDED_BY(PointerData::frame_mutex_);
+std::unordered_map<size_t, std::vector<unwindstack::FrameData>> PointerData::backtraces_info_
+    GUARDED_BY(PointerData::frame_mutex_);
 constexpr size_t kBacktraceEmptyIndex = 1;
 size_t PointerData::cur_hash_index_ GUARDED_BY(PointerData::frame_mutex_);
 
@@ -136,7 +137,7 @@
 
 size_t PointerData::AddBacktrace(size_t num_frames) {
   std::vector<uintptr_t> frames;
-  std::vector<unwindstack::LocalFrameData> frames_info;
+  std::vector<unwindstack::FrameData> frames_info;
   if (g_debug->config().options() & BACKTRACE_FULL) {
     if (!Unwind(&frames, &frames_info, num_frames)) {
       return kBacktraceEmptyIndex;
@@ -386,7 +387,7 @@
     REQUIRES(pointer_mutex_, frame_mutex_) {
   for (const auto& entry : pointers_) {
     FrameInfoType* frame_info = nullptr;
-    std::vector<unwindstack::LocalFrameData>* backtrace_info = nullptr;
+    std::vector<unwindstack::FrameData>* backtrace_info = nullptr;
     size_t hash_index = entry.second.hash_index;
     if (hash_index > kBacktraceEmptyIndex) {
       auto frame_entry = frames_.find(hash_index);
diff --git a/libc/malloc_debug/PointerData.h b/libc/malloc_debug/PointerData.h
index 37d87db..92d2653 100644
--- a/libc/malloc_debug/PointerData.h
+++ b/libc/malloc_debug/PointerData.h
@@ -39,7 +39,7 @@
 #include <vector>
 
 #include <platform/bionic/macros.h>
-#include <unwindstack/LocalUnwinder.h>
+#include <unwindstack/Unwinder.h>
 
 #include "OptionData.h"
 #include "UnwindBacktrace.h"
@@ -109,7 +109,7 @@
   size_t size;
   bool zygote_child_alloc;
   FrameInfoType* frame_info;
-  std::vector<unwindstack::LocalFrameData>* backtrace_info;
+  std::vector<unwindstack::FrameData>* backtrace_info;
 };
 
 class PointerData : public OptionData {
@@ -181,7 +181,7 @@
   static std::mutex frame_mutex_;
   static std::unordered_map<FrameKeyType, size_t> key_to_index_;
   static std::unordered_map<size_t, FrameInfoType> frames_;
-  static std::unordered_map<size_t, std::vector<unwindstack::LocalFrameData>> backtraces_info_;
+  static std::unordered_map<size_t, std::vector<unwindstack::FrameData>> backtraces_info_;
   static size_t cur_hash_index_;
 
   static std::mutex free_pointer_mutex_;
diff --git a/libc/malloc_debug/README.md b/libc/malloc_debug/README.md
index da26d15..662f5f8 100644
--- a/libc/malloc_debug/README.md
+++ b/libc/malloc_debug/README.md
@@ -641,6 +641,13 @@
 for the best way to use malloc debug in Android O or later on non-rooted
 devices.
 
+**NOTE**: Android 12 introduced a bug that can cause the wrap.\<APP\> property to
+no longer work. Use the commands below so that the wrap.\<APP\> instructions will work:
+
+    adb shell setprop dalvik.vm.force-java-zygote-fork-loop true
+    adb shell stop
+    adb shell start
+
 If you do have a rooted device, you can enable malloc debug for a specific
 program/application (Android O or later):
 
diff --git a/libc/malloc_debug/UnwindBacktrace.cpp b/libc/malloc_debug/UnwindBacktrace.cpp
index a7036d9..f6c3e69 100644
--- a/libc/malloc_debug/UnwindBacktrace.cpp
+++ b/libc/malloc_debug/UnwindBacktrace.cpp
@@ -36,8 +36,12 @@
 #include <vector>
 
 #include <android-base/stringprintf.h>
-#include <unwindstack/LocalUnwinder.h>
 #include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+#include <unwindstack/RegsGetLocal.h>
+#include <unwindstack/Unwinder.h>
 
 #include "UnwindBacktrace.h"
 #include "debug_log.h"
@@ -52,42 +56,56 @@
 
 static pthread_once_t g_setup_once = PTHREAD_ONCE_INIT;
 
-static unwindstack::LocalUnwinder* g_unwinder;
-
-static void Setup() {
+static unwindstack::LocalUpdatableMaps* g_maps;
+static std::shared_ptr<unwindstack::Memory> g_process_memory;
 #if defined(__LP64__)
-  std::vector<std::string> skip_libraries{"/system/lib64/libunwindstack.so", "/system/lib64/libc_malloc_debug.so"};
+static std::vector<std::string> g_skip_libraries{"/system/lib64/libunwindstack.so",
+                                                 "/system/lib64/libc_malloc_debug.so"};
 #else
-  std::vector<std::string> skip_libraries{"/system/lib/libunwindstack.so", "/system/lib/libc_malloc_debug.so"};
+static std::vector<std::string> g_skip_libraries{"/system/lib/libunwindstack.so",
+                                                 "/system/lib/libc_malloc_debug.so"};
 #endif
 
-  g_unwinder = new unwindstack::LocalUnwinder(skip_libraries);
-  g_unwinder->Init();
+static void Setup() {
+  g_maps = new unwindstack::LocalUpdatableMaps;
+  if (!g_maps->Parse()) {
+    delete g_maps;
+    g_maps = nullptr;
+  }
+
+  g_process_memory = unwindstack::Memory::CreateProcessMemoryThreadCached(getpid());
 }
 
-bool Unwind(std::vector<uintptr_t>* frames, std::vector<unwindstack::LocalFrameData>* frame_info, size_t max_frames) {
+bool Unwind(std::vector<uintptr_t>* frames, std::vector<unwindstack::FrameData>* frame_info,
+            size_t max_frames) {
   pthread_once(&g_setup_once, Setup);
 
-  if (g_unwinder == nullptr) {
+  if (g_maps == nullptr) {
     return false;
   }
 
-  if (!g_unwinder->Unwind(frame_info, max_frames)) {
+  std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal());
+  unwindstack::RegsGetLocal(regs.get());
+  unwindstack::Unwinder unwinder(max_frames, g_maps, regs.get(), g_process_memory);
+  unwinder.Unwind(&g_skip_libraries);
+  if (unwinder.NumFrames() == 0) {
     frames->clear();
     frame_info->clear();
     return false;
   }
+  *frame_info = unwinder.ConsumeFrames();
 
-  for (const auto& frame : *frame_info) {
-    frames->push_back(frame.pc);
+  frames->resize(frame_info->size());
+  for (size_t i = 0; i < frame_info->size(); i++) {
+    frames->at(i) = frame_info->at(i).pc;
   }
   return true;
 }
 
-void UnwindLog(const std::vector<unwindstack::LocalFrameData>& frame_info) {
+void UnwindLog(const std::vector<unwindstack::FrameData>& frame_info) {
   for (size_t i = 0; i < frame_info.size(); i++) {
-    const unwindstack::LocalFrameData* info = &frame_info[i];
-    std::shared_ptr<unwindstack::MapInfo> map_info = info->map_info;
+    const unwindstack::FrameData* info = &frame_info[i];
+    auto map_info = info->map_info;
 
     std::string line = android::base::StringPrintf("          #%0zd  pc %" PAD_PTR "  ", i, info->rel_pc);
     if (map_info != nullptr && map_info->offset() != 0) {
diff --git a/libc/malloc_debug/UnwindBacktrace.h b/libc/malloc_debug/UnwindBacktrace.h
index 4c6c8d4..7f89907 100644
--- a/libc/malloc_debug/UnwindBacktrace.h
+++ b/libc/malloc_debug/UnwindBacktrace.h
@@ -33,9 +33,10 @@
 #include <string>
 #include <vector>
 
-#include <unwindstack/LocalUnwinder.h>
 #include <unwindstack/MapInfo.h>
+#include <unwindstack/Unwinder.h>
 
-bool Unwind(std::vector<uintptr_t>* frames, std::vector<unwindstack::LocalFrameData>* info, size_t max_frames);
+bool Unwind(std::vector<uintptr_t>* frames, std::vector<unwindstack::FrameData>* info,
+            size_t max_frames);
 
-void UnwindLog(const std::vector<unwindstack::LocalFrameData>& frame_info);
+void UnwindLog(const std::vector<unwindstack::FrameData>& frame_info);
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index d23ab15..9f38946 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -49,6 +49,7 @@
 #include <platform/bionic/reserved_signals.h>
 #include <private/MallocXmlElem.h>
 #include <private/bionic_malloc_dispatch.h>
+#include <unwindstack/Unwinder.h>
 
 #include "Config.h"
 #include "DebugData.h"
@@ -193,7 +194,7 @@
 void BacktraceAndLog() {
   if (g_debug->config().options() & BACKTRACE_FULL) {
     std::vector<uintptr_t> frames;
-    std::vector<unwindstack::LocalFrameData> frames_info;
+    std::vector<unwindstack::FrameData> frames_info;
     if (!Unwind(&frames, &frames_info, 256)) {
       error_log("  Backtrace failed to get any frames.");
     } else {
diff --git a/libc/malloc_debug/tests/backtrace_fake.cpp b/libc/malloc_debug/tests/backtrace_fake.cpp
index ad16c02..f54bae8 100644
--- a/libc/malloc_debug/tests/backtrace_fake.cpp
+++ b/libc/malloc_debug/tests/backtrace_fake.cpp
@@ -20,7 +20,7 @@
 #include <vector>
 #include <utility>
 
-#include <unwindstack/LocalUnwinder.h>
+#include <unwindstack/Unwinder.h>
 
 #include "backtrace.h"
 #include "backtrace_fake.h"
@@ -60,17 +60,17 @@
   }
 }
 
-static std::deque<std::vector<unwindstack::LocalFrameData>> g_fake_local_frame_data;
+static std::deque<std::vector<unwindstack::FrameData>> g_fake_local_frame_data;
 
 void BacktraceUnwindFakeClearAll() {
   g_fake_local_frame_data.clear();
 }
 
-void BacktraceUnwindFake(const std::vector<unwindstack::LocalFrameData>& frames) {
+void BacktraceUnwindFake(const std::vector<unwindstack::FrameData>& frames) {
   g_fake_local_frame_data.push_back(frames);
 }
 
-bool Unwind(std::vector<uintptr_t>* frames, std::vector<unwindstack::LocalFrameData>* info, size_t) {
+bool Unwind(std::vector<uintptr_t>* frames, std::vector<unwindstack::FrameData>* info, size_t) {
   if (g_fake_local_frame_data.empty()) {
     return false;
   }
@@ -85,5 +85,4 @@
   return true;
 }
 
-void UnwindLog(const std::vector<unwindstack::LocalFrameData>& /*frame_info*/) {
-}
+void UnwindLog(const std::vector<unwindstack::FrameData>& /*frame_info*/) {}
diff --git a/libc/malloc_debug/tests/backtrace_fake.h b/libc/malloc_debug/tests/backtrace_fake.h
index a9ee97d..246fc61 100644
--- a/libc/malloc_debug/tests/backtrace_fake.h
+++ b/libc/malloc_debug/tests/backtrace_fake.h
@@ -21,12 +21,12 @@
 
 #include <vector>
 
-#include <unwindstack/LocalUnwinder.h>
+#include <unwindstack/Unwinder.h>
 
 void backtrace_fake_clear_all();
 void backtrace_fake_add(const std::vector<uintptr_t>& ips);
 
 void BacktraceUnwindFakeClearAll();
-void BacktraceUnwindFake(const std::vector<unwindstack::LocalFrameData>& frames);
+void BacktraceUnwindFake(const std::vector<unwindstack::FrameData>& frames);
 
 #endif // MALLOC_DEBUG_TESTS_BACKTRACE_FAKE_H
diff --git a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
index 7b58f31..46de3e9 100644
--- a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
@@ -44,6 +44,8 @@
 #include <platform/bionic/macros.h>
 #include <private/bionic_malloc_dispatch.h>
 
+#include <unwindstack/Unwinder.h>
+
 #include "Config.h"
 #include "malloc_debug.h"
 
@@ -1530,16 +1532,18 @@
   if ((pid = fork()) == 0) {
     std::shared_ptr<unwindstack::MapInfo> empty_map;
     Init("backtrace=4 backtrace_full backtrace_dump_on_exit");
-    BacktraceUnwindFake(std::vector<unwindstack::LocalFrameData>{
-        {empty_map, 0x1100, 0x100, "fake1", 10}, {empty_map, 0x1200, 0x200, "fake2", 20}});
+    BacktraceUnwindFake(
+        std::vector<unwindstack::FrameData>{{0, 0x100, 0x1100, 0, "fake1", 10, empty_map},
+                                            {1, 0x200, 0x1200, 0, "fake2", 20, empty_map}});
     std::shared_ptr<unwindstack::MapInfo> map_info =
         unwindstack::MapInfo::Create(0x10000, 0x20000, 0, PROT_READ | PROT_EXEC, "/data/fake.so");
-    BacktraceUnwindFake(std::vector<unwindstack::LocalFrameData>{
-        {map_info, 0x1a000, 0xa000, "level1", 0}, {map_info, 0x1b000, 0xb000, "level2", 10}});
     BacktraceUnwindFake(
-        std::vector<unwindstack::LocalFrameData>{{empty_map, 0x1a000, 0xa000, "func1", 0},
-                                                 {empty_map, 0x1b000, 0xb000, "func2", 10},
-                                                 {empty_map, 0x1c000, 0xc000, "", 30}});
+        std::vector<unwindstack::FrameData>{{0, 0xa000, 0x1a000, 0, "level1", 0, map_info},
+                                            {1, 0xb000, 0x1b000, 0, "level2", 10, map_info}});
+    BacktraceUnwindFake(
+        std::vector<unwindstack::FrameData>{{0, 0xa000, 0x1a000, 0, "func1", 0, empty_map},
+                                            {1, 0xb000, 0x1b000, 0, "func2", 10, empty_map},
+                                            {2, 0xc000, 0x1c000, 0, "", 30, empty_map}});
 
     std::vector<void*> pointers;
     pointers.push_back(debug_malloc(300));
diff --git a/libc/platform/bionic/pac.h b/libc/platform/bionic/pac.h
index c311651..34efc48 100644
--- a/libc/platform/bionic/pac.h
+++ b/libc/platform/bionic/pac.h
@@ -29,7 +29,6 @@
 #pragma once
 
 #include <stddef.h>
-#include <sys/prctl.h>
 
 inline uintptr_t __bionic_clear_pac_bits(uintptr_t ptr) {
 #if defined(__aarch64__)
@@ -41,39 +40,3 @@
   return ptr;
 #endif
 }
-
-#ifdef __aarch64__
-// The default setting for branch-protection enables both PAC and BTI, so by
-// overriding it to only enable BTI we disable PAC.
-#define __BIONIC_DISABLE_PAUTH __attribute__((target("branch-protection=bti")))
-#else
-#define __BIONIC_DISABLE_PAUTH
-#endif
-
-#ifdef __aarch64__
-// Disable PAC (i.e. make the signing and authentication instructions into no-ops) for the lifetime
-// of this object.
-class ScopedDisablePAC {
-  int prev_enabled_keys_;
-
- public:
-  // Disabling IA will invalidate the return address in this function if it is signed, so we need to
-  // make sure that this function does not sign its return address. Likewise for the destructor.
-  __BIONIC_DISABLE_PAUTH
-  ScopedDisablePAC() {
-    // These prctls will fail (resulting in a no-op, the intended behavior) if PAC is not supported.
-    prev_enabled_keys_ = prctl(PR_PAC_GET_ENABLED_KEYS, 0, 0, 0, 0);
-    prctl(PR_PAC_SET_ENABLED_KEYS, prev_enabled_keys_, 0, 0, 0);
-  }
-
-  __BIONIC_DISABLE_PAUTH
-  ~ScopedDisablePAC() {
-    prctl(PR_PAC_SET_ENABLED_KEYS, prev_enabled_keys_, prev_enabled_keys_, 0, 0);
-  }
-};
-#else
-struct ScopedDisablePAC {
-  // Silence unused variable warnings in non-aarch64 builds.
-  ScopedDisablePAC() {}
-};
-#endif
diff --git a/libfdtrack/Android.bp b/libfdtrack/Android.bp
index fb28623..83ea7cb 100644
--- a/libfdtrack/Android.bp
+++ b/libfdtrack/Android.bp
@@ -38,4 +38,5 @@
     whole_static_libs: ["libBionicCtsGtestMain"],
     static_libs: ["liblog"],
     test_suites: ["device-tests"],
+    runtime_libs: ["libfdtrack"],
 }
diff --git a/libfdtrack/fdtrack.cpp b/libfdtrack/fdtrack.cpp
index 2e9cfbc..2d114f2 100644
--- a/libfdtrack/fdtrack.cpp
+++ b/libfdtrack/fdtrack.cpp
@@ -31,6 +31,8 @@
 
 #include <array>
 #include <mutex>
+#include <string>
+#include <string_view>
 #include <thread>
 #include <utility>
 #include <vector>
@@ -43,11 +45,14 @@
 #include <android-base/thread_annotations.h>
 #include <async_safe/log.h>
 #include <bionic/reserved_signals.h>
-#include <unwindstack/LocalUnwinder.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Regs.h>
+#include <unwindstack/RegsGetLocal.h>
+#include <unwindstack/Unwinder.h>
 
 struct FdEntry {
   std::mutex mutex;
-  std::vector<unwindstack::LocalFrameData> backtrace GUARDED_BY(mutex);
+  std::vector<unwindstack::FrameData> backtrace GUARDED_BY(mutex);
 };
 
 extern "C" void fdtrack_dump();
@@ -62,15 +67,21 @@
 // Backtraces for the first 4k file descriptors ought to be enough to diagnose an fd leak.
 static constexpr size_t kFdTableSize = 4096;
 
-// 32 frames, plus two to skip from fdtrack itself.
-static constexpr size_t kStackDepth = 34;
-static constexpr size_t kStackFrameSkip = 2;
+// Only unwind up to 32 frames outside of libfdtrack.so.
+static constexpr size_t kStackDepth = 32;
+
+// Skip any initial frames from libfdtrack.so.
+static std::vector<std::string> kSkipFdtrackLib [[clang::no_destroy]] = {"libfdtrack.so"};
 
 static bool installed = false;
 static std::array<FdEntry, kFdTableSize> stack_traces [[clang::no_destroy]];
-static unwindstack::LocalUnwinder& Unwinder() {
-  static android::base::NoDestructor<unwindstack::LocalUnwinder> unwinder;
-  return *unwinder.get();
+static unwindstack::LocalUpdatableMaps& Maps() {
+  static android::base::NoDestructor<unwindstack::LocalUpdatableMaps> maps;
+  return *maps.get();
+}
+static std::shared_ptr<unwindstack::Memory>& ProcessMemory() {
+  static android::base::NoDestructor<std::shared_ptr<unwindstack::Memory>> process_memory;
+  return *process_memory.get();
 }
 
 __attribute__((constructor)) static void ctor() {
@@ -89,7 +100,8 @@
   sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
   sigaction(BIONIC_SIGNAL_FDTRACK, &sa, nullptr);
 
-  if (Unwinder().Init()) {
+  if (Maps().Parse()) {
+    ProcessMemory() = unwindstack::Memory::CreateProcessMemoryThreadCached(getpid());
     android_fdtrack_hook_t expected = nullptr;
     installed = android_fdtrack_compare_exchange_hook(&expected, &fd_hook);
   }
@@ -116,7 +128,12 @@
     if (FdEntry* entry = GetFdEntry(event->fd); entry) {
       std::lock_guard<std::mutex> lock(entry->mutex);
       entry->backtrace.clear();
-      Unwinder().Unwind(&entry->backtrace, kStackDepth);
+
+      std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal());
+      unwindstack::RegsGetLocal(regs.get());
+      unwindstack::Unwinder unwinder(kStackDepth, &Maps(), regs.get(), ProcessMemory());
+      unwinder.Unwind(&kSkipFdtrackLib);
+      entry->backtrace = unwinder.ConsumeFrames();
     }
   } else if (event->type == ANDROID_FDTRACK_EVENT_TYPE_CLOSE) {
     if (FdEntry* entry = GetFdEntry(event->fd); entry) {
@@ -153,14 +170,13 @@
       continue;
     }
 
-    for (size_t i = kStackFrameSkip; i < entry->backtrace.size(); ++i) {
-      size_t j = i - kStackFrameSkip;
-      function_names[j] = entry->backtrace[i].function_name.c_str();
-      function_offsets[j] = entry->backtrace[i].function_offset;
+    for (size_t i = 0; i < entry->backtrace.size(); ++i) {
+      function_names[i] = entry->backtrace[i].function_name.c_str();
+      function_offsets[i] = entry->backtrace[i].function_offset;
     }
 
-    bool should_continue = callback(fd, function_names, function_offsets,
-                                    entry->backtrace.size() - kStackFrameSkip, arg);
+    bool should_continue =
+        callback(fd, function_names, function_offsets, entry->backtrace.size(), arg);
 
     entry->mutex.unlock();
 
@@ -200,8 +216,8 @@
     size_t count = 0;
 
     size_t stack_depth = 0;
-    const char* function_names[kStackDepth - kStackFrameSkip];
-    uint64_t function_offsets[kStackDepth - kStackFrameSkip];
+    const char* function_names[kStackDepth];
+    uint64_t function_offsets[kStackDepth];
   };
   struct StackList {
     size_t count = 0;
diff --git a/libm/Android.bp b/libm/Android.bp
index 43d82d5..5622e8c 100644
--- a/libm/Android.bp
+++ b/libm/Android.bp
@@ -307,7 +307,7 @@
             no_libcrt: true,
             shared: {
                 // For backwards-compatibility, some arm32 builtins are exported from libm.so.
-                static_libs: ["libclang_rt.builtins-arm-android-exported"],
+                static_libs: ["libclang_rt.builtins-exported"],
             },
         },
 
diff --git a/linker/Android.bp b/linker/Android.bp
index dbefcf6..d5e7367 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -28,16 +28,11 @@
     name: "linker_wrapper",
     host_supported: true,
     device_supported: false,
+    enabled: false,
     target: {
         linux_bionic: {
             enabled: true,
         },
-        linux_glibc: {
-            enabled: false,
-        },
-        darwin: {
-            enabled: false,
-        },
     },
 
     cflags: [
diff --git a/tests/heap_tagging_level_test.cpp b/tests/heap_tagging_level_test.cpp
index cfb2490..c493e1d 100644
--- a/tests/heap_tagging_level_test.cpp
+++ b/tests/heap_tagging_level_test.cpp
@@ -81,10 +81,20 @@
 #endif // defined(__BIONIC__)
 }
 
+namespace {
 #if defined(__BIONIC__) && defined(__aarch64__)
 void ExitWithSiCode(int, siginfo_t* info, void*) {
   _exit(info->si_code);
 }
+
+template <typename Pred>
+class Or {
+  Pred A, B;
+
+ public:
+  Or(Pred A, Pred B) : A(A), B(B) {}
+  bool operator()(int exit_status) { return A(exit_status) || B(exit_status); }
+};
 #endif
 
 TEST(heap_tagging_level, sync_async_bad_accesses_die) {
@@ -94,6 +104,7 @@
   }
 
   std::unique_ptr<int[]> p = std::make_unique<int[]>(4);
+  volatile int sink ATTRIBUTE_UNUSED;
 
   // We assume that scudo is used on all MTE enabled hardware; scudo inserts a header with a
   // mismatching tag before each allocation.
@@ -104,6 +115,12 @@
         p[-1] = 42;
       },
       testing::ExitedWithCode(SEGV_MTESERR), "");
+  EXPECT_EXIT(
+      {
+        ScopedSignalHandler ssh(SIGSEGV, ExitWithSiCode, SA_SIGINFO);
+        sink = p[-1];
+      },
+      testing::ExitedWithCode(SEGV_MTESERR), "");
 
   EXPECT_TRUE(SetHeapTaggingLevel(M_HEAP_TAGGING_LEVEL_ASYNC));
   EXPECT_EXIT(
@@ -111,14 +128,21 @@
         ScopedSignalHandler ssh(SIGSEGV, ExitWithSiCode, SA_SIGINFO);
         p[-1] = 42;
       },
-      testing::ExitedWithCode(SEGV_MTEAERR), "");
+      Or(testing::ExitedWithCode(SEGV_MTESERR), testing::ExitedWithCode(SEGV_MTEAERR)), "");
+  EXPECT_EXIT(
+      {
+        ScopedSignalHandler ssh(SIGSEGV, ExitWithSiCode, SA_SIGINFO);
+        sink = p[-1];
+      },
+      Or(testing::ExitedWithCode(SEGV_MTESERR), testing::ExitedWithCode(SEGV_MTEAERR)), "");
 
   EXPECT_TRUE(SetHeapTaggingLevel(M_HEAP_TAGGING_LEVEL_NONE));
-  volatile int oob ATTRIBUTE_UNUSED = p[-1];
+  sink = p[-1];
 #else
   GTEST_SKIP() << "bionic/arm64 only";
 #endif
 }
+}  // namespace
 
 TEST(heap_tagging_level, none_pointers_untagged) {
 #if defined(__BIONIC__)
@@ -205,7 +229,9 @@
   const char* kNoteSuffix[] = {"disabled", "async", "sync"};
   const char* kExpectedOutputHWASAN[] = {".*tag-mismatch.*", ".*tag-mismatch.*",
                                          ".*tag-mismatch.*"};
-  const char* kExpectedOutputMTE[] = {"normal exit\n", "SEGV_MTEAERR\n", "SEGV_MTESERR\n"};
+  // Note that we do not check the exact si_code of the "async" variant, as it may be auto-upgraded
+  // to asymm or even sync.
+  const char* kExpectedOutputMTE[] = {"normal exit\n", "SEGV_MTE[AS]ERR\n", "SEGV_MTESERR\n"};
   const char* kExpectedOutputNonMTE[] = {"normal exit\n", "normal exit\n", "normal exit\n"};
   const char** kExpectedOutput =
       withHWASAN ? kExpectedOutputHWASAN : (withMTE ? kExpectedOutputMTE : kExpectedOutputNonMTE);
@@ -215,7 +241,6 @@
   bool isStatic = std::get<1>(GetParam());
   std::string helper_base = std::string("heap_tagging_") + (isStatic ? "static_" : "") +
                             kNoteSuffix[static_cast<int>(note)] + "_helper";
-  fprintf(stderr, "=== %s\n", helper_base.c_str());
   std::string helper = GetTestlibRoot() + "/" + helper_base;
   chmod(helper.c_str(), 0755);
   ExecTestHelper eth;
diff --git a/tests/libs/heap_tagging_helper.cpp b/tests/libs/heap_tagging_helper.cpp
index 1a970f2..16a8c8b 100644
--- a/tests/libs/heap_tagging_helper.cpp
+++ b/tests/libs/heap_tagging_helper.cpp
@@ -16,7 +16,9 @@
 
 #include <signal.h>
 #include <stdio.h>
+#include <sys/auxv.h>
 #include <sys/cdefs.h>
+#include <sys/mman.h>
 #include <unistd.h>
 #include <memory>
 
@@ -37,6 +39,11 @@
   _exit(0);
 }
 
+void action2(int signo, siginfo_t* info __unused, void*) {
+  fprintf(stderr, "unexpected signal %d\n", signo);
+  _exit(0);
+}
+
 __attribute__((optnone)) int main() {
   struct sigaction sa = {};
   sa.sa_sigaction = action;
@@ -47,6 +54,37 @@
   volatile int oob = p[-1];
   (void)oob;
 
+#if defined(__BIONIC__) && defined(__aarch64__)
+  // If we get here, bad access on system heap memory did not trigger a fault.
+  // This suggests that MTE is disabled. Make sure that explicitly tagged PROT_MTE memory does not
+  // trigger a fault either.
+  if (getauxval(AT_HWCAP2) & HWCAP2_MTE) {
+    sa.sa_sigaction = action2;
+    sigaction(SIGSEGV, &sa, nullptr);
+
+    size_t page_size = static_cast<size_t>(sysconf(_SC_PAGESIZE));
+    void* p = mmap(nullptr, page_size, PROT_READ | PROT_WRITE | PROT_MTE,
+                   MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+    if (!p) {
+      fprintf(stderr, "mmap failed\n");
+      return 1;
+    }
+
+    void* q = p;
+    __asm__ __volatile__(
+        ".arch_extension memtag\n"
+        "irg %[Ptr], %[Ptr], xzr\n"
+        "stg %[Ptr], [%[Ptr]]\n"
+        "addg %[Ptr], %[Ptr], 0, 1\n"
+        "str xzr, [%[Ptr]]\n"
+        : [Ptr] "+&r"(q)
+        :
+        : "memory");
+
+    munmap(p, page_size);
+  }
+#endif  // __aarch64__
+
   fprintf(stderr, "normal exit\n");
   return 0;
 }
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index e38dd60..87031f6 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -364,10 +364,13 @@
 
 TEST_F(STDIO_DEATHTEST, snprintf_n) {
 #if defined(__BIONIC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat"
   // http://b/14492135 and http://b/31832608.
   char buf[32];
   int i = 1234;
   EXPECT_DEATH(snprintf(buf, sizeof(buf), "a %n b", &i), "%n not allowed on Android");
+#pragma GCC diagnostic pop
 #else
   GTEST_SKIP() << "glibc does allow %n";
 #endif