xref: /aosp_15_r20/system/core/debuggerd/libdebuggerd/test/mte_stack_record_test.cpp (revision 00c7fec1bb09f3284aad6a6f96d2f63dfc3650ad)
1 /*
2  * Copyright (C) 2024 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 #if defined(__aarch64__)
17 
18 #include <stdint.h>
19 #include <sys/mman.h>
20 
21 #include <optional>
22 
23 #include "bionic/mte.h"
24 #include "bionic/page.h"
25 #include "unwindstack/AndroidUnwinder.h"
26 #include "unwindstack/Memory.h"
27 
28 #include <android-base/test_utils.h>
29 #include <procinfo/process_map.h>
30 
31 #include "gtest/gtest.h"
32 
33 #include "libdebuggerd/tombstone.h"
34 
35 struct ScopedUnmap {
36   void* ptr;
37   size_t size;
~ScopedUnmapScopedUnmap38   ~ScopedUnmap() { munmap(ptr, size); }
39 };
40 
41 class MteStackHistoryTest : public ::testing::TestWithParam<int> {
SetUp()42   void SetUp() override {
43 #if !defined(__aarch64__)
44     GTEST_SKIP();
45 #endif
46     SKIP_WITH_HWASAN;
47     unwinder.emplace();
48     unwindstack::ErrorData E;
49     ASSERT_TRUE(unwinder->Initialize(E));
50   }
51 
52  protected:
53   // std::optional so we don't construct it for the SKIP cases.
54   std::optional<unwindstack::AndroidLocalUnwinder> unwinder;
55 };
56 
TEST(MteStackHistoryUnwindTest,TestOne)57 TEST(MteStackHistoryUnwindTest, TestOne) {
58 #if !defined(__aarch64__)
59   GTEST_SKIP();
60 #endif
61   SKIP_WITH_HWASAN;
62   size_t size = stack_mte_ringbuffer_size(0);
63   char* data = static_cast<char*>(stack_mte_ringbuffer_allocate(0, nullptr));
64   ScopedUnmap s{data, size};
65 
66   uintptr_t taggedfp = (1ULL << 56) | 1;
67   uintptr_t pc = reinterpret_cast<uintptr_t>(&memcpy);
68   memcpy(data, &pc, sizeof(pc));
69   memcpy(data + 8, &taggedfp, sizeof(taggedfp));
70 
71   // The MTE TLS is at TLS - 3, so we allocate 3 placeholders.
72   void* tls[4] = {data + 16};
73 
74   unwindstack::AndroidLocalUnwinder unwinder;
75   unwindstack::ErrorData E;
76   unwinder.Initialize(E);
77   StackHistoryBuffer shb;
78   dump_stack_history(&unwinder, reinterpret_cast<uintptr_t>(&tls[3]), shb, /* nounwind= */ false);
79   ASSERT_EQ(shb.entries_size(), 1);
80   const StackHistoryBufferEntry& e = shb.entries(0);
81   EXPECT_EQ(e.addr().pc(), pc);
82   EXPECT_EQ(e.addr().file_name(), "/apex/com.android.runtime/lib64/bionic/libc.so");
83   EXPECT_EQ(e.fp(), 1ULL);
84   EXPECT_EQ(e.tag(), 1ULL);
85 }
86 
FindMapping(void * data)87 static std::optional<android::procinfo::MapInfo> FindMapping(void* data) {
88   std::optional<android::procinfo::MapInfo> result;
89   android::procinfo::ReadMapFile(
90       "/proc/self/maps", [&result, data](const android::procinfo::MapInfo& info) {
91         auto data_int = reinterpret_cast<uint64_t>(data) & ((1ULL << 56ULL) - 1ULL);
92         if (info.start <= data_int && data_int < info.end) {
93           result = info;
94         }
95       });
96   return result;
97 }
98 
TEST_P(MteStackHistoryTest,TestFree)99 TEST_P(MteStackHistoryTest, TestFree) {
100   int size_cls = GetParam();
101   size_t size = stack_mte_ringbuffer_size(size_cls);
102   void* data = stack_mte_ringbuffer_allocate(size_cls, nullptr);
103   EXPECT_EQ(stack_mte_ringbuffer_size_from_pointer(reinterpret_cast<uintptr_t>(data)), size);
104   auto before = FindMapping(data);
105   ASSERT_TRUE(before.has_value());
106   EXPECT_EQ(before->end - before->start, size);
107   stack_mte_free_ringbuffer(reinterpret_cast<uintptr_t>(data));
108   for (size_t i = 0; i < size; i += page_size()) {
109     auto after = FindMapping(static_cast<char*>(data) + i);
110     EXPECT_TRUE(!after.has_value() || after->name != before->name);
111   }
112 }
113 
TEST_P(MteStackHistoryTest,TestEmpty)114 TEST_P(MteStackHistoryTest, TestEmpty) {
115   int size_cls = GetParam();
116   size_t size = stack_mte_ringbuffer_size(size_cls);
117   void* data = stack_mte_ringbuffer_allocate(size_cls, nullptr);
118   ScopedUnmap s{data, size};
119   // The MTE TLS is at TLS - 3, so we allocate 3 placeholders.
120   void* tls[4] = {data};
121 
122   StackHistoryBuffer shb;
123   dump_stack_history(&*unwinder, reinterpret_cast<uintptr_t>(&tls[3]), shb, /* nounwind= */ true);
124   EXPECT_EQ(shb.entries_size(), 0);
125 }
126 
TEST_P(MteStackHistoryTest,TestFull)127 TEST_P(MteStackHistoryTest, TestFull) {
128   int size_cls = GetParam();
129   size_t size = stack_mte_ringbuffer_size(size_cls);
130   char* data = static_cast<char*>(stack_mte_ringbuffer_allocate(size_cls, nullptr));
131   ScopedUnmap s{data, size};
132   uintptr_t itr = 1;
133   for (char* d = data; d < &data[size]; d += 16) {
134     uintptr_t taggedfp = ((itr & 15) << 56) | itr;
135     uintptr_t pc = itr;
136     memcpy(d, &pc, sizeof(pc));
137     memcpy(d + 8, &taggedfp, sizeof(taggedfp));
138     ++itr;
139   }
140   // The MTE TLS is at TLS - 3, so we allocate 3 placeholders.
141   // Because the buffer is full, and we point at one past the last inserted element,
142   // due to wrap-around we point at the beginning of the buffer.
143   void* tls[4] = {data};
144 
145   StackHistoryBuffer shb;
146   dump_stack_history(&*unwinder, reinterpret_cast<uintptr_t>(&tls[3]), shb, /* nounwind= */ true);
147   EXPECT_EQ(static_cast<size_t>(shb.entries_size()), size / 16);
148   for (const auto& entry : shb.entries()) {
149     EXPECT_EQ(entry.addr().pc(), --itr);
150     EXPECT_EQ(entry.addr().pc(), entry.fp());
151     EXPECT_EQ(entry.addr().pc() & 15, entry.tag());
152   }
153 }
154 
TEST_P(MteStackHistoryTest,TestHalfFull)155 TEST_P(MteStackHistoryTest, TestHalfFull) {
156   int size_cls = GetParam();
157   size_t size = stack_mte_ringbuffer_size(size_cls);
158   size_t half_size = size / 2;
159 
160   char* data = static_cast<char*>(stack_mte_ringbuffer_allocate(size_cls, nullptr));
161   ScopedUnmap s{data, size};
162 
163   uintptr_t itr = 1;
164   for (char* d = data; d < &data[half_size]; d += 16) {
165     uintptr_t taggedfp = ((itr & 15) << 56) | itr;
166     uintptr_t pc = itr;
167     memcpy(d, &pc, sizeof(pc));
168     memcpy(d + 8, &taggedfp, sizeof(taggedfp));
169     ++itr;
170   }
171   // The MTE TLS is at TLS - 3, so we allocate 3 placeholders.
172   void* tls[4] = {&data[half_size]};
173 
174   StackHistoryBuffer shb;
175   dump_stack_history(&*unwinder, reinterpret_cast<uintptr_t>(&tls[3]), shb, /* nounwind= */ true);
176   EXPECT_EQ(static_cast<size_t>(shb.entries_size()), half_size / 16);
177   for (const auto& entry : shb.entries()) {
178     EXPECT_EQ(entry.addr().pc(), --itr);
179     EXPECT_EQ(entry.addr().pc(), entry.fp());
180     EXPECT_EQ(entry.addr().pc() & 15, entry.tag());
181   }
182 }
183 
184 INSTANTIATE_TEST_SUITE_P(MteStackHistoryTestInstance, MteStackHistoryTest, testing::Range(0, 8));
185 
186 #endif
187