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/LocalUnwinder.h>
22 #include <unwindstack/Unwinder.h>
23
24 namespace gwp_asan {
25 namespace options {
26
27 // In reality, on Android, we use two separate unwinders. GWP-ASan internally
28 // uses a fast, frame-pointer unwinder for allocation/deallocation stack traces
29 // (android_unsafe_frame_pointer_chase, provided by bionic libc). When a process
30 // crashes, debuggerd unwinds the access trace using libunwindstack, which is a
31 // slow CFI-based unwinder. We don't split the unwinders in the test harness,
32 // and frame-pointer unwinding doesn't work properly though a signal handler, so
33 // we opt to use libunwindstack in this test. This has the effect that we get
34 // potentially more detailed stack frames in the allocation/deallocation traces
35 // (as we don't use the production unwinder), but that's fine for test-only.
BacktraceUnwindstack(uintptr_t * TraceBuffer,size_t Size)36 size_t BacktraceUnwindstack(uintptr_t *TraceBuffer, size_t Size) {
37 unwindstack::LocalUnwinder unwinder;
38 if (!unwinder.Init()) {
39 return 0;
40 }
41 std::vector<unwindstack::LocalFrameData> frames;
42 if (!unwinder.Unwind(&frames, Size)) {
43 return 0;
44 }
45 for (const auto& frame : frames) {
46 *TraceBuffer = frame.pc;
47 TraceBuffer++;
48 }
49 return frames.size();
50 }
51
getBacktraceFunction()52 Backtrace_t getBacktraceFunction() {
53 return BacktraceUnwindstack;
54 }
55
56 // Build a frame for symbolization using the maps from the provided unwinder.
57 // The constructed frame contains just enough information to be used to
58 // symbolize a GWP-ASan stack trace.
BuildFrame(unwindstack::Unwinder * unwinder,uintptr_t pc)59 static unwindstack::FrameData BuildFrame(unwindstack::Unwinder* unwinder, uintptr_t pc) {
60 unwindstack::FrameData frame;
61
62 unwindstack::Maps* maps = unwinder->GetMaps();
63 unwindstack::MapInfo* map_info = maps->Find(pc);
64 if (!map_info) {
65 frame.rel_pc = pc;
66 return frame;
67 }
68
69 unwindstack::Elf* elf =
70 map_info->GetElf(unwinder->GetProcessMemory(), unwindstack::Regs::CurrentArch());
71
72 uint64_t relative_pc = elf->GetRelPc(pc, map_info);
73
74 // Create registers just to get PC adjustment. Doesn't matter what they point
75 // to.
76 unwindstack::Regs* regs = unwindstack::Regs::CreateFromLocal();
77 uint64_t pc_adjustment = regs->GetPcAdjustment(relative_pc, elf);
78 relative_pc -= pc_adjustment;
79 // The debug PC may be different if the PC comes from the JIT.
80 uint64_t debug_pc = relative_pc;
81
82 // If we don't have a valid ELF file, check the JIT.
83 if (!elf->valid()) {
84 unwindstack::JitDebug jit_debug(unwinder->GetProcessMemory());
85 uint64_t jit_pc = pc - pc_adjustment;
86 unwindstack::Elf* jit_elf = jit_debug.GetElf(maps, jit_pc);
87 if (jit_elf != nullptr) {
88 debug_pc = jit_pc;
89 elf = jit_elf;
90 }
91 }
92
93 // Copy all the things we need into the frame for symbolization.
94 frame.rel_pc = relative_pc;
95 frame.pc = pc - pc_adjustment;
96 frame.map_name = map_info->name;
97 frame.map_elf_start_offset = map_info->elf_start_offset;
98 frame.map_exact_offset = map_info->offset;
99 frame.map_start = map_info->start;
100 frame.map_end = map_info->end;
101 frame.map_flags = map_info->flags;
102 frame.map_load_bias = elf->GetLoadBias();
103
104 if (!elf->GetFunctionName(relative_pc, &frame.function_name, &frame.function_offset)) {
105 frame.function_name = "";
106 frame.function_offset = 0;
107 }
108 return frame;
109 }
110
111 // This function is a good mimic as to what's happening in the out-of-process
112 // tombstone daemon (see debuggerd for more information). In our case, we want
113 // to provide symbolized backtraces during ***testing only*** here. This
114 // function called from a signal handler, and is extraordinarily not
115 // signal-safe, but works for our purposes.
PrintBacktraceUnwindstack(uintptr_t * TraceBuffer,size_t TraceLength,crash_handler::Printf_t Print)116 void PrintBacktraceUnwindstack(uintptr_t *TraceBuffer, size_t TraceLength,
117 crash_handler::Printf_t Print) {
118 unwindstack::UnwinderFromPid unwinder(
119 AllocationMetadata::kMaxTraceLengthToCollect, getpid());
120 unwinder.Init(unwindstack::Regs::CurrentArch());
121 unwinder.SetRegs(unwindstack::Regs::CreateFromLocal());
122
123 for (size_t i = 0; i < TraceLength; ++i) {
124 unwindstack::FrameData frame_data = BuildFrame(&unwinder, TraceBuffer[i]);
125 frame_data.num = i;
126 Print(" %s\n", unwinder.FormatFrame(frame_data).c_str());
127 }
128 }
129
getPrintBacktraceFunction()130 crash_handler::PrintBacktrace_t getPrintBacktraceFunction() {
131 return PrintBacktraceUnwindstack;
132 }
133 } // namespace options
134 } // namespace gwp_asan
135