summaryrefslogtreecommitdiff
path: root/base/trace_event/cfi_backtrace_android_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'base/trace_event/cfi_backtrace_android_unittest.cc')
-rw-r--r--base/trace_event/cfi_backtrace_android_unittest.cc197
1 files changed, 197 insertions, 0 deletions
diff --git a/base/trace_event/cfi_backtrace_android_unittest.cc b/base/trace_event/cfi_backtrace_android_unittest.cc
new file mode 100644
index 0000000000..3ad3d33042
--- /dev/null
+++ b/base/trace_event/cfi_backtrace_android_unittest.cc
@@ -0,0 +1,197 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/cfi_backtrace_android.h"
+
+#include "base/files/file_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+void* GetPC() {
+ return __builtin_return_address(0);
+}
+
+} // namespace
+
+TEST(CFIBacktraceAndroidTest, TestUnwinding) {
+ auto* unwinder = CFIBacktraceAndroid::GetInitializedInstance();
+ EXPECT_TRUE(unwinder->can_unwind_stack_frames());
+ EXPECT_GT(unwinder->executable_start_addr_, 0u);
+ EXPECT_GT(unwinder->executable_end_addr_, unwinder->executable_start_addr_);
+ EXPECT_GT(unwinder->cfi_mmap_->length(), 0u);
+
+ const size_t kMaxFrames = 100;
+ const void* frames[kMaxFrames];
+ size_t unwind_count = unwinder->Unwind(frames, kMaxFrames);
+ // Expect at least 2 frames in the result.
+ ASSERT_GT(unwind_count, 2u);
+ EXPECT_LE(unwind_count, kMaxFrames);
+
+ const size_t kMaxCurrentFuncCodeSize = 50;
+ const uintptr_t current_pc = reinterpret_cast<uintptr_t>(GetPC());
+ const uintptr_t actual_frame = reinterpret_cast<uintptr_t>(frames[2]);
+ EXPECT_NEAR(current_pc, actual_frame, kMaxCurrentFuncCodeSize);
+
+ for (size_t i = 0; i < unwind_count; ++i) {
+ EXPECT_GT(reinterpret_cast<uintptr_t>(frames[i]),
+ unwinder->executable_start_addr_);
+ EXPECT_LT(reinterpret_cast<uintptr_t>(frames[i]),
+ unwinder->executable_end_addr_);
+ }
+}
+
+// Flaky: https://bugs.chromium.org/p/chromium/issues/detail?id=829555
+TEST(CFIBacktraceAndroidTest, DISABLED_TestFindCFIRow) {
+ auto* unwinder = CFIBacktraceAndroid::GetInitializedInstance();
+ /* Input is generated from the CFI file:
+ STACK CFI INIT 1000 500
+ STACK CFI 1002 .cfa: sp 272 + .ra: .cfa -4 + ^ r4: .cfa -16 +
+ STACK CFI 1008 .cfa: sp 544 + .r1: .cfa -0 + ^ r4: .cfa -16 + ^
+ STACK CFI 1040 .cfa: sp 816 + .r1: .cfa -0 + ^ r4: .cfa -16 + ^
+ STACK CFI 1050 .cfa: sp 816 + .ra: .cfa -8 + ^ r4: .cfa -16 + ^
+ STACK CFI 1080 .cfa: sp 544 + .r1: .cfa -0 + ^ r4: .cfa -16 + ^
+
+ STACK CFI INIT 2000 22
+ STACK CFI 2004 .cfa: sp 16 + .ra: .cfa -12 + ^ r4: .cfa -16 + ^
+ STACK CFI 2008 .cfa: sp 16 + .ra: .cfa -12 + ^ r4: .cfa -16 + ^
+
+ STACK CFI INIT 2024 100
+ STACK CFI 2030 .cfa: sp 48 + .ra: .cfa -12 + ^ r4: .cfa -16 + ^
+ STACK CFI 2100 .cfa: sp 64 + .r1: .cfa -0 + ^ r4: .cfa -16 + ^
+
+ STACK CFI INIT 2200 10
+ STACK CFI 2204 .cfa: sp 44 + .ra: .cfa -8 + ^ r4: .cfa -16 + ^
+ */
+ uint16_t input[] = {// UNW_INDEX size
+ 0x2A,
+
+ // UNW_INDEX address column (4 byte rows).
+ 0x0, 0x1000, 0x0, 0x1502, 0x0, 0x2000, 0x0, 0x2024, 0x0,
+ 0x2126, 0x0, 0x2200, 0x0, 0x2212, 0x0,
+
+ // UNW_INDEX index column (2 byte rows).
+ 0x0, 0xffff, 0xb, 0x10, 0xffff, 0x15, 0xffff,
+
+ // UNW_DATA table.
+ 0x5, 0x2, 0x111, 0x8, 0x220, 0x40, 0x330, 0x50, 0x332,
+ 0x80, 0x220, 0x2, 0x4, 0x13, 0x8, 0x13, 0x2, 0xc, 0x33,
+ 0xdc, 0x40, 0x1, 0x4, 0x2e};
+ FilePath temp_path;
+ CreateTemporaryFile(&temp_path);
+ EXPECT_EQ(
+ static_cast<int>(sizeof(input)),
+ WriteFile(temp_path, reinterpret_cast<char*>(input), sizeof(input)));
+
+ unwinder->cfi_mmap_.reset(new MemoryMappedFile());
+ unwinder->cfi_mmap_->Initialize(temp_path);
+ unwinder->ParseCFITables();
+
+ CFIBacktraceAndroid::CFIRow cfi_row = {0};
+ EXPECT_FALSE(unwinder->FindCFIRowForPC(0x01, &cfi_row));
+ EXPECT_FALSE(unwinder->FindCFIRowForPC(0x100, &cfi_row));
+ EXPECT_FALSE(unwinder->FindCFIRowForPC(0x1502, &cfi_row));
+ EXPECT_FALSE(unwinder->FindCFIRowForPC(0x3000, &cfi_row));
+ EXPECT_FALSE(unwinder->FindCFIRowForPC(0x2024, &cfi_row));
+ EXPECT_FALSE(unwinder->FindCFIRowForPC(0x2212, &cfi_row));
+
+ const CFIBacktraceAndroid::CFIRow kRow1 = {0x110, 0x4};
+ const CFIBacktraceAndroid::CFIRow kRow2 = {0x220, 0x4};
+ const CFIBacktraceAndroid::CFIRow kRow3 = {0x220, 0x8};
+ const CFIBacktraceAndroid::CFIRow kRow4 = {0x30, 0xc};
+ const CFIBacktraceAndroid::CFIRow kRow5 = {0x2c, 0x8};
+ EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1002, &cfi_row));
+ EXPECT_EQ(kRow1, cfi_row);
+ EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1003, &cfi_row));
+ EXPECT_EQ(kRow1, cfi_row);
+ EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1008, &cfi_row));
+ EXPECT_EQ(kRow2, cfi_row);
+ EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1009, &cfi_row));
+ EXPECT_EQ(kRow2, cfi_row);
+ EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1039, &cfi_row));
+ EXPECT_EQ(kRow2, cfi_row);
+ EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1080, &cfi_row));
+ EXPECT_EQ(kRow3, cfi_row);
+ EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1100, &cfi_row));
+ EXPECT_EQ(kRow3, cfi_row);
+ EXPECT_TRUE(unwinder->FindCFIRowForPC(0x2050, &cfi_row));
+ EXPECT_EQ(kRow4, cfi_row);
+ EXPECT_TRUE(unwinder->FindCFIRowForPC(0x2208, &cfi_row));
+ EXPECT_EQ(kRow5, cfi_row);
+ EXPECT_TRUE(unwinder->FindCFIRowForPC(0x2210, &cfi_row));
+ EXPECT_EQ(kRow5, cfi_row);
+
+ // Test if cache is used on the future calls to Find, all addresses should
+ // have different hash. Resetting the memory map to make sure it is never
+ // accessed in Find().
+ unwinder->cfi_mmap_.reset(new MemoryMappedFile());
+ EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1002, &cfi_row));
+ EXPECT_EQ(kRow1, cfi_row);
+ EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1003, &cfi_row));
+ EXPECT_EQ(kRow1, cfi_row);
+ EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1008, &cfi_row));
+ EXPECT_EQ(kRow2, cfi_row);
+ EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1009, &cfi_row));
+ EXPECT_EQ(kRow2, cfi_row);
+ EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1039, &cfi_row));
+ EXPECT_EQ(kRow2, cfi_row);
+ EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1080, &cfi_row));
+ EXPECT_EQ(kRow3, cfi_row);
+ EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1100, &cfi_row));
+ EXPECT_EQ(kRow3, cfi_row);
+ EXPECT_TRUE(unwinder->FindCFIRowForPC(0x2050, &cfi_row));
+ EXPECT_EQ(kRow4, cfi_row);
+ EXPECT_TRUE(unwinder->FindCFIRowForPC(0x2208, &cfi_row));
+ EXPECT_EQ(kRow5, cfi_row);
+ EXPECT_TRUE(unwinder->FindCFIRowForPC(0x2210, &cfi_row));
+ EXPECT_EQ(kRow5, cfi_row);
+}
+
+TEST(CFIBacktraceAndroidTest, TestCFICache) {
+ // Use ASSERT macros in this function since they are in loop and using EXPECT
+ // prints too many failures.
+ CFIBacktraceAndroid::CFICache cache;
+ CFIBacktraceAndroid::CFIRow cfi;
+
+ // Empty cache should not find anything.
+ EXPECT_FALSE(cache.Find(1, &cfi));
+
+ // Insert 1 - 2*kLimit
+ for (size_t i = 1; i <= 2 * cache.kLimit; ++i) {
+ CFIBacktraceAndroid::CFIRow val = {4 * i, 2 * i};
+ cache.Add(i, val);
+ ASSERT_TRUE(cache.Find(i, &cfi));
+ ASSERT_EQ(cfi, val);
+
+ // Inserting more than kLimit items evicts |i - cache.kLimit| from cache.
+ if (i >= cache.kLimit)
+ ASSERT_FALSE(cache.Find(i - cache.kLimit, &cfi));
+ }
+ // Cache contains kLimit+1 - 2*kLimit.
+
+ // Check that 1 - kLimit cannot be found.
+ for (size_t i = 1; i <= cache.kLimit; ++i) {
+ ASSERT_FALSE(cache.Find(i, &cfi));
+ }
+
+ // Check if kLimit+1 - 2*kLimit still exists in cache.
+ for (size_t i = cache.kLimit + 1; i <= 2 * cache.kLimit; ++i) {
+ CFIBacktraceAndroid::CFIRow val = {4 * i, 2 * i};
+ ASSERT_TRUE(cache.Find(i, &cfi));
+ ASSERT_EQ(cfi, val);
+ }
+
+ // Insert 2*kLimit+1, will evict kLimit.
+ cfi = {1, 1};
+ cache.Add(2 * cache.kLimit + 1, cfi);
+ EXPECT_TRUE(cache.Find(2 * cache.kLimit + 1, &cfi));
+ EXPECT_FALSE(cache.Find(cache.kLimit + 1, &cfi));
+ // Cache contains kLimit+1 - 2*kLimit.
+}
+
+} // namespace trace_event
+} // namespace base