1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "gwp_asan/common.h"
18 #include "gwp_asan/optional/backtrace.h"
19 #include "gwp_asan/optional/segv_handler.h"
20
21 #include <unwindstack/Maps.h>
22 #include <unwindstack/Memory.h>
23 #include <unwindstack/Regs.h>
24 #include <unwindstack/RegsGetLocal.h>
25 #include <unwindstack/Unwinder.h>
26
27 namespace {
28 // In reality, on Android, we use two separate unwinders. GWP-ASan internally
29 // uses a fast, frame-pointer unwinder for allocation/deallocation stack traces
30 // (android_unsafe_frame_pointer_chase, provided by bionic libc). When a process
31 // crashes, debuggerd unwinds the access trace using libunwindstack, which is a
32 // slow CFI-based unwinder. We don't split the unwinders in the test harness,
33 // and frame-pointer unwinding doesn't work properly though a signal handler, so
34 // we opt to use libunwindstack in this test. This has the effect that we get
35 // potentially more detailed stack frames in the allocation/deallocation traces
36 // (as we don't use the production unwinder), but that's fine for test-only.
BacktraceUnwindstack(uintptr_t * TraceBuffer,size_t Size)37 size_t BacktraceUnwindstack(uintptr_t *TraceBuffer, size_t Size) {
38 unwindstack::LocalMaps maps;
39 if (!maps.Parse()) {
40 return 0;
41 }
42
43 auto process_memory = unwindstack::Memory::CreateProcessMemoryThreadCached(getpid());
44 std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal());
45 unwindstack::RegsGetLocal(regs.get());
46 unwindstack::Unwinder unwinder(Size, &maps, regs.get(), process_memory);
47 unwinder.Unwind();
48 for (const auto &frame : unwinder.frames()) {
49 *TraceBuffer = frame.pc;
50 TraceBuffer++;
51 }
52 return unwinder.NumFrames();
53 }
54
55 // We don't need any custom handling for the Segv backtrace - the unwindstack
56 // unwinder has no problems with unwinding through a signal handler.
SegvBacktrace(uintptr_t * TraceBuffer,size_t Size,void *)57 size_t SegvBacktrace(uintptr_t *TraceBuffer, size_t Size, void * /*Context*/) {
58 return BacktraceUnwindstack(TraceBuffer, Size);
59 }
60
61 // This function is a good mimic as to what's happening in the out-of-process
62 // tombstone daemon (see debuggerd for more information). In our case, we want
63 // to provide symbolized backtraces during ***testing only*** here. This
64 // function called from a signal handler, and is extraordinarily not
65 // signal-safe, but works for our purposes.
PrintBacktraceUnwindstack(uintptr_t * TraceBuffer,size_t TraceLength,gwp_asan::Printf_t Print)66 void PrintBacktraceUnwindstack(uintptr_t *TraceBuffer, size_t TraceLength,
67 gwp_asan::Printf_t Print) {
68 unwindstack::UnwinderFromPid unwinder(
69 gwp_asan::AllocationMetadata::kMaxTraceLengthToCollect, getpid());
70 unwinder.SetRegs(unwindstack::Regs::CreateFromLocal());
71 if (!unwinder.Init()) {
72 Print(" Unable to init unwinder: %s\n", unwinder.LastErrorCodeString());
73 return;
74 }
75
76 for (size_t i = 0; i < TraceLength; ++i) {
77 unwindstack::FrameData frame_data =
78 unwinder.BuildFrameFromPcOnly(TraceBuffer[i]);
79 frame_data.num = i;
80 Print(" %s\n", unwinder.FormatFrame(frame_data).c_str());
81 }
82 }
83
84 } // anonymous namespace
85
86 namespace gwp_asan {
87 namespace backtrace {
getBacktraceFunction()88 options::Backtrace_t getBacktraceFunction() { return BacktraceUnwindstack; }
89
getPrintBacktraceFunction()90 PrintBacktrace_t getPrintBacktraceFunction() {
91 return PrintBacktraceUnwindstack;
92 }
93
getSegvBacktraceFunction()94 SegvBacktrace_t getSegvBacktraceFunction() { return SegvBacktrace; }
95 } // namespace backtrace
96 } // namespace gwp_asan
97