Snap for 6357023 from 241d18d8f30995bc883dfcb15f69dd36658864a5 to rvc-release
Change-Id: Id6c2a90cf14179aa25f62d5d3e7ac77bcb57760e
diff --git a/Android.bp b/Android.bp
index 25abe52..5fa7e11 100644
--- a/Android.bp
+++ b/Android.bp
@@ -130,14 +130,28 @@
"gwp_asan_crash_handler",
"libasync_safe",
"liblog",
+ "libunwindstack",
+ "liblzma", // Dependency from libunwindstack.
+ ],
+
+ ldflags: [
+ // Ensure that ICF doesn't clobber DeallocateMemory2 into
+ // DeallocateMemory in tests/backtrace.cpp. This is done in the linker,
+ // so `optnone` in the function declaration doesn't help.
+ "-Wl,--icf=none",
],
srcs: [
+ "android/test_backtrace.cpp",
"android/test_printf.cpp",
+ "gwp_asan/optional/segv_handler_posix.cpp",
"gwp_asan/tests/alignment.cpp",
+ "gwp_asan/tests/backtrace.cpp",
"gwp_asan/tests/basic.cpp",
"gwp_asan/tests/compression.cpp",
"gwp_asan/tests/crash_handler_api.cpp",
+ "gwp_asan/tests/enable_disable.cpp",
"gwp_asan/tests/harness.cpp",
+ "gwp_asan/tests/iterate.cpp",
"gwp_asan/tests/late_init.cpp",
"gwp_asan/tests/mutex_test.cpp",
"gwp_asan/tests/slot_reuse.cpp",
@@ -145,7 +159,19 @@
],
include_dirs: ["bionic/libc/async_safe/include"],
test_suites: ["general-tests"],
- cflags: ["-fno-emulated-tls"],
+ cflags: [
+ // GWP-ASan requires anything that uses GuardedPoolAllocator headers to
+ // use platform (ELF) TLS.
+ "-fno-emulated-tls",
+
+ // Ensure that the helper functions in test/backtrace.cpp don't get
+ // tail-call optimised, as this breaks the unwind chain.
+ "-fno-optimize-sibling-calls",
+
+ // The experimental pass manager seems to kill __attribute__((optnone)),
+ // and so we disable it (as we rely on optnone for tests/backtrace.cpp).
+ "-fno-experimental-new-pass-manager",
+ ],
// Late initialisation tests should run isolated, as the platform IE TLS
// PRNG should be initialised to its default state.
diff --git a/android/test_backtrace.cpp b/android/test_backtrace.cpp
new file mode 100644
index 0000000..193f490
--- /dev/null
+++ b/android/test_backtrace.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gwp_asan/common.h"
+#include "gwp_asan/optional/backtrace.h"
+#include "gwp_asan/optional/segv_handler.h"
+
+#include <unwindstack/LocalUnwinder.h>
+#include <unwindstack/Unwinder.h>
+
+namespace gwp_asan {
+namespace options {
+
+// In reality, on Android, we use two separate unwinders. GWP-ASan internally
+// uses a fast, frame-pointer unwinder for allocation/deallocation stack traces
+// (android_unsafe_frame_pointer_chase, provided by bionic libc). When a process
+// crashes, debuggerd unwinds the access trace using libunwindstack, which is a
+// slow CFI-based unwinder. We don't split the unwinders in the test harness,
+// and frame-pointer unwinding doesn't work properly though a signal handler, so
+// we opt to use libunwindstack in this test. This has the effect that we get
+// potentially more detailed stack frames in the allocation/deallocation traces
+// (as we don't use the production unwinder), but that's fine for test-only.
+size_t BacktraceUnwindstack(uintptr_t *TraceBuffer, size_t Size) {
+ unwindstack::LocalUnwinder unwinder;
+ if (!unwinder.Init()) {
+ return 0;
+ }
+ std::vector<unwindstack::LocalFrameData> frames;
+ if (!unwinder.Unwind(&frames, Size)) {
+ return 0;
+ }
+ for (const auto& frame : frames) {
+ *TraceBuffer = frame.pc;
+ TraceBuffer++;
+ }
+ return frames.size();
+}
+
+Backtrace_t getBacktraceFunction() {
+ return BacktraceUnwindstack;
+}
+
+// Build a frame for symbolization using the maps from the provided unwinder.
+// The constructed frame contains just enough information to be used to
+// symbolize a GWP-ASan stack trace.
+static unwindstack::FrameData BuildFrame(unwindstack::Unwinder* unwinder, uintptr_t pc) {
+ unwindstack::FrameData frame;
+
+ unwindstack::Maps* maps = unwinder->GetMaps();
+ unwindstack::MapInfo* map_info = maps->Find(pc);
+ if (!map_info) {
+ frame.rel_pc = pc;
+ return frame;
+ }
+
+ unwindstack::Elf* elf =
+ map_info->GetElf(unwinder->GetProcessMemory(), unwindstack::Regs::CurrentArch());
+
+ uint64_t relative_pc = elf->GetRelPc(pc, map_info);
+
+ // Create registers just to get PC adjustment. Doesn't matter what they point
+ // to.
+ unwindstack::Regs* regs = unwindstack::Regs::CreateFromLocal();
+ uint64_t pc_adjustment = regs->GetPcAdjustment(relative_pc, elf);
+ relative_pc -= pc_adjustment;
+ // The debug PC may be different if the PC comes from the JIT.
+ uint64_t debug_pc = relative_pc;
+
+ // If we don't have a valid ELF file, check the JIT.
+ if (!elf->valid()) {
+ unwindstack::JitDebug jit_debug(unwinder->GetProcessMemory());
+ uint64_t jit_pc = pc - pc_adjustment;
+ unwindstack::Elf* jit_elf = jit_debug.GetElf(maps, jit_pc);
+ if (jit_elf != nullptr) {
+ debug_pc = jit_pc;
+ elf = jit_elf;
+ }
+ }
+
+ // Copy all the things we need into the frame for symbolization.
+ frame.rel_pc = relative_pc;
+ frame.pc = pc - pc_adjustment;
+ frame.map_name = map_info->name;
+ frame.map_elf_start_offset = map_info->elf_start_offset;
+ frame.map_exact_offset = map_info->offset;
+ frame.map_start = map_info->start;
+ frame.map_end = map_info->end;
+ frame.map_flags = map_info->flags;
+ frame.map_load_bias = elf->GetLoadBias();
+
+ if (!elf->GetFunctionName(relative_pc, &frame.function_name, &frame.function_offset)) {
+ frame.function_name = "";
+ frame.function_offset = 0;
+ }
+ return frame;
+}
+
+// This function is a good mimic as to what's happening in the out-of-process
+// tombstone daemon (see debuggerd for more information). In our case, we want
+// to provide symbolized backtraces during ***testing only*** here. This
+// function called from a signal handler, and is extraordinarily not
+// signal-safe, but works for our purposes.
+void PrintBacktraceUnwindstack(uintptr_t *TraceBuffer, size_t TraceLength,
+ crash_handler::Printf_t Print) {
+ unwindstack::UnwinderFromPid unwinder(
+ AllocationMetadata::kMaxTraceLengthToCollect, getpid());
+ unwinder.Init(unwindstack::Regs::CurrentArch());
+ unwinder.SetRegs(unwindstack::Regs::CreateFromLocal());
+
+ for (size_t i = 0; i < TraceLength; ++i) {
+ unwindstack::FrameData frame_data = BuildFrame(&unwinder, TraceBuffer[i]);
+ frame_data.num = i;
+ Print(" %s\n", unwinder.FormatFrame(frame_data).c_str());
+ }
+}
+
+crash_handler::PrintBacktrace_t getPrintBacktraceFunction() {
+ return PrintBacktraceUnwindstack;
+}
+} // namespace options
+} // namespace gwp_asan
diff --git a/android/test_printf.cpp b/android/test_printf.cpp
index 086b0aa..27bb0de 100644
--- a/android/test_printf.cpp
+++ b/android/test_printf.cpp
@@ -9,7 +9,7 @@
void PrintfWrapper(const char *Format, ...) {
va_list List;
va_start(List, Format);
- async_safe_format_log_va_list(ANDROID_LOG_FATAL, "GWP-ASan", Format, List);
+ async_safe_fatal_va_list("GWP-ASan", Format, List);
va_end(List);
}
}; // anonymous namespace