• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and use spans.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "base/trace_event/cfi_backtrace_android.h"
11 
12 #include "base/files/file_util.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 
15 namespace base {
16 namespace trace_event {
17 
18 namespace {
19 
GetPC()20 void* GetPC() {
21   return __builtin_return_address(0);
22 }
23 
24 }  // namespace
25 
TEST(CFIBacktraceAndroidTest,TestUnwinding)26 TEST(CFIBacktraceAndroidTest, TestUnwinding) {
27   auto* unwinder = CFIBacktraceAndroid::GetInitializedInstance();
28   EXPECT_TRUE(unwinder->can_unwind_stack_frames());
29   EXPECT_GT(unwinder->executable_start_addr(), 0u);
30   EXPECT_GT(unwinder->executable_end_addr(), unwinder->executable_start_addr());
31   EXPECT_GT(unwinder->cfi_mmap_->length(), 0u);
32 
33   const size_t kMaxFrames = 100;
34   const void* frames[kMaxFrames];
35   size_t unwind_count = unwinder->Unwind(frames, kMaxFrames);
36   // Expect at least 2 frames in the result.
37   ASSERT_GT(unwind_count, 2u);
38   EXPECT_LE(unwind_count, kMaxFrames);
39 
40   const size_t kMaxCurrentFuncCodeSize = 50;
41   const uintptr_t current_pc = reinterpret_cast<uintptr_t>(GetPC());
42   const uintptr_t actual_frame = reinterpret_cast<uintptr_t>(frames[2]);
43   EXPECT_NEAR(current_pc, actual_frame, kMaxCurrentFuncCodeSize);
44 
45   for (size_t i = 0; i < unwind_count; ++i) {
46     EXPECT_GT(reinterpret_cast<uintptr_t>(frames[i]),
47               unwinder->executable_start_addr());
48     EXPECT_LT(reinterpret_cast<uintptr_t>(frames[i]),
49               unwinder->executable_end_addr());
50   }
51 }
52 
53 // Flaky: https://bugs.chromium.org/p/chromium/issues/detail?id=829555
TEST(CFIBacktraceAndroidTest,DISABLED_TestFindCFIRow)54 TEST(CFIBacktraceAndroidTest, DISABLED_TestFindCFIRow) {
55   auto* unwinder = CFIBacktraceAndroid::GetInitializedInstance();
56   /* Input is generated from the CFI file:
57   STACK CFI INIT 1000 500
58   STACK CFI 1002 .cfa: sp 272 + .ra: .cfa -4 + ^ r4: .cfa -16 +
59   STACK CFI 1008 .cfa: sp 544 + .r1: .cfa -0 + ^ r4: .cfa -16 + ^
60   STACK CFI 1040 .cfa: sp 816 + .r1: .cfa -0 + ^ r4: .cfa -16 + ^
61   STACK CFI 1050 .cfa: sp 816 + .ra: .cfa -8 + ^ r4: .cfa -16 + ^
62   STACK CFI 1080 .cfa: sp 544 + .r1: .cfa -0 + ^ r4: .cfa -16 + ^
63 
64   STACK CFI INIT 2000 22
65   STACK CFI 2004 .cfa: sp 16 + .ra: .cfa -12 + ^ r4: .cfa -16 + ^
66   STACK CFI 2008 .cfa: sp 16 + .ra: .cfa -12 + ^ r4: .cfa -16 + ^
67 
68   STACK CFI INIT 2024 100
69   STACK CFI 2030 .cfa: sp 48 + .ra: .cfa -12 + ^ r4: .cfa -16 + ^
70   STACK CFI 2100 .cfa: sp 64 + .r1: .cfa -0 + ^ r4: .cfa -16 + ^
71 
72   STACK CFI INIT 2200 10
73   STACK CFI 2204 .cfa: sp 44 + .ra: .cfa -8 + ^ r4: .cfa -16 + ^
74   */
75   uint16_t input[] = {// UNW_INDEX size
76                       0x07, 0x0,
77 
78                       // UNW_INDEX address column (4 byte rows).
79                       0x1000, 0x0, 0x1502, 0x0, 0x2000, 0x0, 0x2024, 0x0,
80                       0x2126, 0x0, 0x2200, 0x0, 0x2212, 0x0,
81 
82                       // UNW_INDEX index column (2 byte rows).
83                       0x0, 0xffff, 0xb, 0x10, 0xffff, 0x15, 0xffff,
84 
85                       // UNW_DATA table.
86                       0x5, 0x2, 0x111, 0x8, 0x220, 0x40, 0x330, 0x50, 0x332,
87                       0x80, 0x220, 0x2, 0x4, 0x13, 0x8, 0x13, 0x2, 0xc, 0x33,
88                       0xdc, 0x40, 0x1, 0x4, 0x2e};
89   FilePath temp_path;
90   CreateTemporaryFile(&temp_path);
91   EXPECT_TRUE(WriteFile(temp_path, as_byte_span(input)));
92 
93   unwinder->cfi_mmap_.reset(new MemoryMappedFile());
94   ASSERT_TRUE(unwinder->cfi_mmap_->Initialize(temp_path));
95   unwinder->ParseCFITables();
96 
97   CFIBacktraceAndroid::CFIRow cfi_row = {0};
98   EXPECT_FALSE(unwinder->FindCFIRowForPC(0x01, &cfi_row));
99   EXPECT_FALSE(unwinder->FindCFIRowForPC(0x100, &cfi_row));
100   EXPECT_FALSE(unwinder->FindCFIRowForPC(0x1502, &cfi_row));
101   EXPECT_FALSE(unwinder->FindCFIRowForPC(0x3000, &cfi_row));
102   EXPECT_FALSE(unwinder->FindCFIRowForPC(0x2024, &cfi_row));
103   EXPECT_FALSE(unwinder->FindCFIRowForPC(0x2212, &cfi_row));
104 
105   const CFIBacktraceAndroid::CFIRow kRow1 = {0x110, 0x4};
106   const CFIBacktraceAndroid::CFIRow kRow2 = {0x220, 0x4};
107   const CFIBacktraceAndroid::CFIRow kRow3 = {0x220, 0x8};
108   const CFIBacktraceAndroid::CFIRow kRow4 = {0x30, 0xc};
109   const CFIBacktraceAndroid::CFIRow kRow5 = {0x2c, 0x8};
110   EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1002, &cfi_row));
111   EXPECT_EQ(kRow1, cfi_row);
112   EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1003, &cfi_row));
113   EXPECT_EQ(kRow1, cfi_row);
114   EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1008, &cfi_row));
115   EXPECT_EQ(kRow2, cfi_row);
116   EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1009, &cfi_row));
117   EXPECT_EQ(kRow2, cfi_row);
118   EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1039, &cfi_row));
119   EXPECT_EQ(kRow2, cfi_row);
120   EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1080, &cfi_row));
121   EXPECT_EQ(kRow3, cfi_row);
122   EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1100, &cfi_row));
123   EXPECT_EQ(kRow3, cfi_row);
124   EXPECT_TRUE(unwinder->FindCFIRowForPC(0x2050, &cfi_row));
125   EXPECT_EQ(kRow4, cfi_row);
126   EXPECT_TRUE(unwinder->FindCFIRowForPC(0x2208, &cfi_row));
127   EXPECT_EQ(kRow5, cfi_row);
128   EXPECT_TRUE(unwinder->FindCFIRowForPC(0x2210, &cfi_row));
129   EXPECT_EQ(kRow5, cfi_row);
130 
131   // Test if cache is used on the future calls to Find, all addresses should
132   // have different hash. Resetting the memory map to make sure it is never
133   // accessed in Find().
134   unwinder->cfi_mmap_.reset(new MemoryMappedFile());
135   EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1002, &cfi_row));
136   EXPECT_EQ(kRow1, cfi_row);
137   EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1003, &cfi_row));
138   EXPECT_EQ(kRow1, cfi_row);
139   EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1008, &cfi_row));
140   EXPECT_EQ(kRow2, cfi_row);
141   EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1009, &cfi_row));
142   EXPECT_EQ(kRow2, cfi_row);
143   EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1039, &cfi_row));
144   EXPECT_EQ(kRow2, cfi_row);
145   EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1080, &cfi_row));
146   EXPECT_EQ(kRow3, cfi_row);
147   EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1100, &cfi_row));
148   EXPECT_EQ(kRow3, cfi_row);
149   EXPECT_TRUE(unwinder->FindCFIRowForPC(0x2050, &cfi_row));
150   EXPECT_EQ(kRow4, cfi_row);
151   EXPECT_TRUE(unwinder->FindCFIRowForPC(0x2208, &cfi_row));
152   EXPECT_EQ(kRow5, cfi_row);
153   EXPECT_TRUE(unwinder->FindCFIRowForPC(0x2210, &cfi_row));
154   EXPECT_EQ(kRow5, cfi_row);
155 }
156 
TEST(CFIBacktraceAndroidTest,TestCFICache)157 TEST(CFIBacktraceAndroidTest, TestCFICache) {
158   // Use ASSERT macros in this function since they are in loop and using EXPECT
159   // prints too many failures.
160   CFIBacktraceAndroid::CFICache cache;
161   CFIBacktraceAndroid::CFIRow cfi;
162 
163   // Empty cache should not find anything.
164   EXPECT_FALSE(cache.Find(1, &cfi));
165 
166   // Insert 1 - 2*kLimit
167   for (uintptr_t i = 1; i <= 2 * cache.kLimit; ++i) {
168     CFIBacktraceAndroid::CFIRow val = {static_cast<uint16_t>(4 * i),
169                                        static_cast<uint16_t>(2 * i)};
170     cache.Add(i, val);
171     ASSERT_TRUE(cache.Find(i, &cfi));
172     ASSERT_EQ(cfi, val);
173 
174     // Inserting more than kLimit items evicts |i - cache.kLimit| from cache.
175     if (i >= cache.kLimit)
176       ASSERT_FALSE(cache.Find(i - cache.kLimit, &cfi));
177   }
178   // Cache contains kLimit+1 - 2*kLimit.
179 
180   // Check that 1 - kLimit cannot be found.
181   for (uintptr_t i = 1; i <= cache.kLimit; ++i) {
182     ASSERT_FALSE(cache.Find(i, &cfi));
183   }
184 
185   // Check if kLimit+1 - 2*kLimit still exists in cache.
186   for (uintptr_t i = cache.kLimit + 1; i <= 2 * cache.kLimit; ++i) {
187     CFIBacktraceAndroid::CFIRow val = {static_cast<uint16_t>(4 * i),
188                                        static_cast<uint16_t>(2 * i)};
189     ASSERT_TRUE(cache.Find(i, &cfi));
190     ASSERT_EQ(cfi, val);
191   }
192 
193   // Insert 2*kLimit+1, will evict kLimit.
194   cfi = {1, 1};
195   cache.Add(2 * cache.kLimit + 1, cfi);
196   EXPECT_TRUE(cache.Find(2 * cache.kLimit + 1, &cfi));
197   EXPECT_FALSE(cache.Find(cache.kLimit + 1, &cfi));
198   // Cache contains kLimit+1 - 2*kLimit.
199 }
200 
201 }  // namespace trace_event
202 }  // namespace base
203