• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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