blob: efec85288f08fa942154787e44490a0f48d0aad1 [file] [log] [blame]
Magnus Jedvert7510e4a2019-01-20 11:46:32 +01001/*
2 * Copyright 2019 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "sdk/android/native_api/stacktrace/stacktrace.h"
12#include <dlfcn.h>
13#include <vector>
14#include "absl/memory/memory.h"
Steve Antonf3802842019-01-24 19:07:40 -080015#include "rtc_base/critical_section.h"
Magnus Jedvert7510e4a2019-01-20 11:46:32 +010016#include "rtc_base/event.h"
17#include "rtc_base/logging.h"
18#include "rtc_base/platform_thread.h"
19#include "rtc_base/strings/string_builder.h"
20#include "test/gtest.h"
21
22namespace webrtc {
23namespace test {
24
25// Returns the execution address relative to the .so base address. This matches
26// the addresses we get from GetStacktrace().
27uint32_t GetCurrentRelativeExecutionAddress() {
28 void* pc = __builtin_return_address(0);
29 Dl_info dl_info = {};
30 const bool success = dladdr(pc, &dl_info);
31 EXPECT_TRUE(success);
32 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(pc) -
33 reinterpret_cast<uintptr_t>(dl_info.dli_fbase));
34}
35
36// Returns true if any of the stack trace element is inside the specified
37// region.
38bool StackTraceContainsRange(const std::vector<StackTraceElement>& stack_trace,
39 uintptr_t pc_low,
40 uintptr_t pc_high) {
41 for (const StackTraceElement& stack_trace_element : stack_trace) {
42 if (pc_low <= stack_trace_element.relative_address &&
43 pc_high >= stack_trace_element.relative_address) {
44 return true;
45 }
46 }
47 return false;
48}
49
50class DeadlockInterface {
51 public:
52 virtual ~DeadlockInterface() {}
53
54 // This function should deadlock until Release() is called.
55 virtual void Deadlock() = 0;
56
57 // This function should release the thread stuck in Deadlock().
58 virtual void Release() = 0;
59};
60
61struct ThreadParams {
62 volatile int tid;
63 // Signaled when the deadlock region is entered.
64 rtc::Event deadlock_start_event;
65 DeadlockInterface* volatile deadlock_impl;
66 // Defines an address range within the deadlock will occur.
67 volatile uint32_t deadlock_region_start_address;
68 volatile uint32_t deadlock_region_end_address;
69 // Signaled when the deadlock is done.
70 rtc::Event deadlock_done_event;
71};
72
73class RtcEventDeadlock : public DeadlockInterface {
74 private:
75 void Deadlock() override { event.Wait(rtc::Event::kForever); }
76 void Release() override { event.Set(); }
77
78 rtc::Event event;
79};
80
81class RtcCriticalSectionDeadlock : public DeadlockInterface {
82 public:
83 RtcCriticalSectionDeadlock()
84 : critscope_(absl::make_unique<rtc::CritScope>(&crit_)) {}
85
86 private:
87 void Deadlock() override { rtc::CritScope lock(&crit_); }
88
89 void Release() override { critscope_.reset(); }
90
91 rtc::CriticalSection crit_;
92 std::unique_ptr<rtc::CritScope> critscope_;
93};
94
95class SpinDeadlock : public DeadlockInterface {
96 public:
97 SpinDeadlock() : is_deadlocked_(true) {}
98
99 private:
100 void Deadlock() override {
101 while (is_deadlocked_) {
102 }
103 }
104
105 void Release() override { is_deadlocked_ = false; }
106
107 std::atomic<bool> is_deadlocked_;
108};
109
110class SleepDeadlock : public DeadlockInterface {
111 private:
112 void Deadlock() override { sleep(1000000); }
113
114 void Release() override {
115 // The interrupt itself will break free from the sleep.
116 }
117};
118
119// This is the function that is exectued by the thread that will deadlock and
120// have its stacktrace captured.
121void ThreadFunction(void* void_params) {
122 ThreadParams* params = static_cast<ThreadParams*>(void_params);
123 params->tid = gettid();
124
125 params->deadlock_region_start_address = GetCurrentRelativeExecutionAddress();
126 params->deadlock_start_event.Set();
127 params->deadlock_impl->Deadlock();
128 params->deadlock_region_end_address = GetCurrentRelativeExecutionAddress();
129
130 params->deadlock_done_event.Set();
131}
132
133void TestStacktrace(std::unique_ptr<DeadlockInterface> deadlock_impl) {
134 // Set params that will be sent to other thread.
135 ThreadParams params;
136 params.deadlock_impl = deadlock_impl.get();
137
138 // Spawn thread.
139 rtc::PlatformThread thread(&ThreadFunction, &params, "StacktraceTest");
140 thread.Start();
141
142 // Wait until the thread has entered the deadlock region.
143 params.deadlock_start_event.Wait(rtc::Event::kForever);
144
145 // Acquire the stack trace of the thread which should now be deadlocking.
146 std::vector<StackTraceElement> stack_trace = GetStackTrace(params.tid);
147
148 // Release the deadlock so that the thread can continue.
149 deadlock_impl->Release();
150
151 // Wait until the thread has left the deadlock.
152 params.deadlock_done_event.Wait(rtc::Event::kForever);
153
154 // Assert that the stack trace contains the deadlock region.
155 EXPECT_TRUE(StackTraceContainsRange(stack_trace,
156 params.deadlock_region_start_address,
157 params.deadlock_region_end_address))
158 << "Deadlock region: ["
159 << rtc::ToHex(params.deadlock_region_start_address) << ", "
160 << rtc::ToHex(params.deadlock_region_end_address)
161 << "] not contained in: " << StackTraceToString(stack_trace);
162
163 thread.Stop();
164}
165
Karl Wibergc130d422019-02-28 17:06:54 +0100166TEST(Stacktrace, TestCurrentThread) {
167 const uint32_t start_addr = GetCurrentRelativeExecutionAddress();
168 const std::vector<StackTraceElement> stack_trace = GetStackTrace();
169 const uint32_t end_addr = GetCurrentRelativeExecutionAddress();
170 EXPECT_TRUE(StackTraceContainsRange(stack_trace, start_addr, end_addr))
171 << "Caller region: [" << rtc::ToHex(start_addr) << ", "
172 << rtc::ToHex(end_addr)
173 << "] not contained in: " << StackTraceToString(stack_trace);
174}
175
Magnus Jedvert7510e4a2019-01-20 11:46:32 +0100176TEST(Stacktrace, TestSpinLock) {
177 TestStacktrace(absl::make_unique<SpinDeadlock>());
178}
179
180TEST(Stacktrace, TestSleep) {
181 TestStacktrace(absl::make_unique<SleepDeadlock>());
182}
183
184// Stack traces originating from kernel space does not include user space stack
185// traces for ARM 32.
186#ifdef WEBRTC_ARCH_ARM64
187TEST(Stacktrace, TestRtcEvent) {
188 TestStacktrace(absl::make_unique<RtcEventDeadlock>());
189}
190
191TEST(Stacktrace, TestRtcCriticalSection) {
192 TestStacktrace(absl::make_unique<RtcCriticalSectionDeadlock>());
193}
194#endif
195
196} // namespace test
197} // namespace webrtc