1 //===-- sanitizer_stacktrace_test.cpp -------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file is a part of ThreadSanitizer/AddressSanitizer runtime. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "sanitizer_common/sanitizer_common.h" 14 #include "sanitizer_common/sanitizer_stacktrace.h" 15 #include "gtest/gtest.h" 16 17 namespace __sanitizer { 18 19 class FastUnwindTest : public ::testing::Test { 20 protected: 21 virtual void SetUp(); 22 virtual void TearDown(); 23 24 void UnwindFast(); 25 26 void *mapping; 27 uhwptr *fake_stack; 28 const uptr fake_stack_size = 10; 29 uhwptr start_pc; 30 31 uhwptr fake_bp; 32 uhwptr fake_top; 33 uhwptr fake_bottom; 34 BufferedStackTrace trace; 35 36 #if defined(__riscv) 37 const uptr kFpOffset = 4; 38 const uptr kBpOffset = 2; 39 #else 40 const uptr kFpOffset = 2; 41 const uptr kBpOffset = 0; 42 #endif 43 }; 44 45 static uptr PC(uptr idx) { 46 return (1<<20) + idx; 47 } 48 49 void FastUnwindTest::SetUp() { 50 size_t ps = GetPageSize(); 51 mapping = MmapOrDie(2 * ps, "FastUnwindTest"); 52 MprotectNoAccess((uptr)mapping, ps); 53 54 // Unwinder may peek 1 word down from the starting FP. 55 fake_stack = (uhwptr *)((uptr)mapping + ps + sizeof(uhwptr)); 56 57 // Fill an array of pointers with fake fp+retaddr pairs. Frame pointers have 58 // even indices. 59 for (uptr i = 0; i + 1 < fake_stack_size; i += 2) { 60 fake_stack[i] = (uptr)&fake_stack[i + kFpOffset]; // fp 61 fake_stack[i+1] = PC(i + 1); // retaddr 62 } 63 // Mark the last fp point back up to terminate the stack trace. 64 fake_stack[RoundDownTo(fake_stack_size - 1, 2)] = (uhwptr)&fake_stack[0]; 65 66 // Top is two slots past the end because UnwindFast subtracts two. 67 fake_top = (uhwptr)&fake_stack[fake_stack_size + kFpOffset]; 68 // Bottom is one slot before the start because UnwindFast uses >. 69 fake_bottom = (uhwptr)mapping; 70 fake_bp = (uptr)&fake_stack[kBpOffset]; 71 start_pc = PC(0); 72 } 73 74 void FastUnwindTest::TearDown() { 75 size_t ps = GetPageSize(); 76 UnmapOrDie(mapping, 2 * ps); 77 } 78 79 #if SANITIZER_CAN_FAST_UNWIND 80 81 #ifdef __sparc__ 82 // Fake stacks don't meet SPARC UnwindFast requirements. 83 #define SKIP_ON_SPARC(x) DISABLED_##x 84 #else 85 #define SKIP_ON_SPARC(x) x 86 #endif 87 88 void FastUnwindTest::UnwindFast() { 89 trace.UnwindFast(start_pc, fake_bp, fake_top, fake_bottom, kStackTraceMax); 90 } 91 92 TEST_F(FastUnwindTest, SKIP_ON_SPARC(Basic)) { 93 UnwindFast(); 94 // Should get all on-stack retaddrs and start_pc. 95 EXPECT_EQ(6U, trace.size); 96 EXPECT_EQ(start_pc, trace.trace[0]); 97 for (uptr i = 1; i <= 5; i++) { 98 EXPECT_EQ(PC(i*2 - 1), trace.trace[i]); 99 } 100 } 101 102 // From: https://github.com/google/sanitizers/issues/162 103 TEST_F(FastUnwindTest, SKIP_ON_SPARC(FramePointerLoop)) { 104 // Make one fp point to itself. 105 fake_stack[4] = (uhwptr)&fake_stack[4]; 106 UnwindFast(); 107 // Should get all on-stack retaddrs up to the 4th slot and start_pc. 108 EXPECT_EQ(4U, trace.size); 109 EXPECT_EQ(start_pc, trace.trace[0]); 110 for (uptr i = 1; i <= 3; i++) { 111 EXPECT_EQ(PC(i*2 - 1), trace.trace[i]); 112 } 113 } 114 115 TEST_F(FastUnwindTest, SKIP_ON_SPARC(MisalignedFramePointer)) { 116 // Make one fp misaligned. 117 fake_stack[4] += 3; 118 UnwindFast(); 119 // Should get all on-stack retaddrs up to the 4th slot and start_pc. 120 EXPECT_EQ(4U, trace.size); 121 EXPECT_EQ(start_pc, trace.trace[0]); 122 for (uptr i = 1; i < 4U; i++) { 123 EXPECT_EQ(PC(i*2 - 1), trace.trace[i]); 124 } 125 } 126 127 TEST_F(FastUnwindTest, OneFrameStackTrace) { 128 trace.Unwind(start_pc, fake_bp, nullptr, true, 1); 129 EXPECT_EQ(1U, trace.size); 130 EXPECT_EQ(start_pc, trace.trace[0]); 131 EXPECT_EQ((uhwptr)&fake_stack[kBpOffset], trace.top_frame_bp); 132 } 133 134 TEST_F(FastUnwindTest, ZeroFramesStackTrace) { 135 trace.Unwind(start_pc, fake_bp, nullptr, true, 0); 136 EXPECT_EQ(0U, trace.size); 137 EXPECT_EQ(0U, trace.top_frame_bp); 138 } 139 140 TEST_F(FastUnwindTest, SKIP_ON_SPARC(FPBelowPrevFP)) { 141 // The next FP points to unreadable memory inside the stack limits, but below 142 // current FP. 143 fake_stack[0] = (uhwptr)&fake_stack[-50]; 144 fake_stack[1] = PC(1); 145 UnwindFast(); 146 EXPECT_EQ(2U, trace.size); 147 EXPECT_EQ(PC(0), trace.trace[0]); 148 EXPECT_EQ(PC(1), trace.trace[1]); 149 } 150 151 TEST_F(FastUnwindTest, SKIP_ON_SPARC(CloseToZeroFrame)) { 152 // Make one pc a NULL pointer. 153 fake_stack[5] = 0x0; 154 UnwindFast(); 155 // The stack should be truncated at the NULL pointer (and not include it). 156 EXPECT_EQ(3U, trace.size); 157 EXPECT_EQ(start_pc, trace.trace[0]); 158 for (uptr i = 1; i < 3U; i++) { 159 EXPECT_EQ(PC(i*2 - 1), trace.trace[i]); 160 } 161 } 162 163 #endif // SANITIZER_CAN_FAST_UNWIND 164 165 TEST(SlowUnwindTest, ShortStackTrace) { 166 BufferedStackTrace stack; 167 uptr pc = StackTrace::GetCurrentPc(); 168 uptr bp = GET_CURRENT_FRAME(); 169 stack.Unwind(pc, bp, nullptr, false, /*max_depth=*/0); 170 EXPECT_EQ(0U, stack.size); 171 EXPECT_EQ(0U, stack.top_frame_bp); 172 stack.Unwind(pc, bp, nullptr, false, /*max_depth=*/1); 173 EXPECT_EQ(1U, stack.size); 174 EXPECT_EQ(pc, stack.trace[0]); 175 EXPECT_EQ(bp, stack.top_frame_bp); 176 } 177 178 } // namespace __sanitizer 179