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