/* * 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 #include namespace { // 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 frames; if (!unwinder.Unwind(&frames, Size)) { return 0; } for (const auto &frame : frames) { *TraceBuffer = frame.pc; TraceBuffer++; } return frames.size(); } // We don't need any custom handling for the Segv backtrace - the unwindstack // unwinder has no problems with unwinding through a signal handler. size_t SegvBacktrace(uintptr_t *TraceBuffer, size_t Size, void * /*Context*/) { return BacktraceUnwindstack(TraceBuffer, Size); } // 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, gwp_asan::Printf_t Print) { unwindstack::UnwinderFromPid unwinder( gwp_asan::AllocationMetadata::kMaxTraceLengthToCollect, getpid()); unwinder.SetRegs(unwindstack::Regs::CreateFromLocal()); if (!unwinder.Init()) { Print(" Unable to init unwinder: %s\n", unwinder.LastErrorCodeString()); return; } for (size_t i = 0; i < TraceLength; ++i) { unwindstack::FrameData frame_data = unwinder.BuildFrameFromPcOnly(TraceBuffer[i]); frame_data.num = i; Print(" %s\n", unwinder.FormatFrame(frame_data).c_str()); } } } // anonymous namespace namespace gwp_asan { namespace backtrace { options::Backtrace_t getBacktraceFunction() { return BacktraceUnwindstack; } PrintBacktrace_t getPrintBacktraceFunction() { return PrintBacktraceUnwindstack; } SegvBacktrace_t getSegvBacktraceFunction() { return SegvBacktrace; } } // namespace backtrace } // namespace gwp_asan