xref: /aosp_15_r20/external/gwp_asan/android/test_backtrace.cpp (revision b302aa5039729da396909ef03e815160dab4448c)
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