Revert "Android: Add helper methods for printing native stack traces"
This reverts commit dc32cc00e80972223767be339f9318b803f4a2ae.
Reason for revert: Seems to be breaking Chromium FYI, https://www.google.com/url?q=https://ci.chromium.org/p/chromium/builders/luci.chromium.webrtc.fyi/WebRTC%2520Chromium%2520FYI%2520Android%2520Tests%2520%2528dbg%2529%2520%2528K%2520Nexus5%2529/1807&sa=D&source=hangouts&ust=1548149426180000&usg=AFQjCNGh9aBqv2wNE12D8-6rn9-AJR-cNg
Original change's description:
> Android: Add helper methods for printing native stack traces
>
> This CL adds utility functions to unwind the stack for a given thread on
> Android ARM devices. This works on top of unwind.h and unwinds native
> (C++) stack traces only. Unwinding a thread from another thread is done
> by overriding the signal handler with a custom function and then
> interrupting the specific thread.
>
> Bug: webrtc:10168
> Change-Id: If5adffd3a6bb57bf502168743e09a7eefc292bf3
> Reviewed-on: https://webrtc-review.googlesource.com/c/118141
> Commit-Queue: Magnus Jedvert <magjed@webrtc.org>
> Reviewed-by: Tommi <tommi@webrtc.org>
> Cr-Commit-Position: refs/heads/master@{#26328}
TBR=magjed@webrtc.org,tommi@webrtc.org
Change-Id: I6e01f9226ef60777cb422baeab042bce8944f9ed
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: webrtc:10168
Reviewed-on: https://webrtc-review.googlesource.com/c/118683
Reviewed-by: Magnus Jedvert <magjed@webrtc.org>
Commit-Queue: Magnus Jedvert <magjed@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26336}
diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn
index 534865e..60b5517 100644
--- a/sdk/android/BUILD.gn
+++ b/sdk/android/BUILD.gn
@@ -68,7 +68,6 @@
":native_api_codecs",
":native_api_jni",
":native_api_peerconnection",
- ":native_api_stacktrace",
":native_api_video",
]
}
@@ -981,19 +980,6 @@
]
}
- # API for capturing and printing native stacktraces.
- rtc_static_library("native_api_stacktrace") {
- visibility = [ "*" ]
- sources = [
- "native_api/stacktrace/stacktrace.cc",
- "native_api/stacktrace/stacktrace.h",
- ]
-
- deps = [
- "../../rtc_base",
- ]
- }
-
# API for creating C++ wrapper implementations of api/mediastreaminterface.h
# video interfaces from their Java equivalents.
rtc_static_library("native_api_video") {
@@ -1526,7 +1512,6 @@
"native_unittests/codecs/wrapper_unittest.cc",
"native_unittests/java_types_unittest.cc",
"native_unittests/peerconnection/peer_connection_factory_unittest.cc",
- "native_unittests/stacktrace/stacktrace_unittest.cc",
"native_unittests/test_jni_onload.cc",
"native_unittests/video/video_source_unittest.cc",
]
@@ -1552,7 +1537,6 @@
":native_api_codecs",
":native_api_jni",
":native_api_peerconnection",
- ":native_api_stacktrace",
":native_api_video",
":opensles_audio_device_module",
":video_jni",
diff --git a/sdk/android/native_api/stacktrace/stacktrace.cc b/sdk/android/native_api/stacktrace/stacktrace.cc
deleted file mode 100644
index 8268ff5..0000000
--- a/sdk/android/native_api/stacktrace/stacktrace.cc
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Copyright 2019 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "sdk/android/native_api/stacktrace/stacktrace.h"
-
-#include <dlfcn.h>
-#include <errno.h>
-#include <linux/futex.h>
-#include <sys/ptrace.h>
-#include <sys/ucontext.h>
-#include <syscall.h>
-#include <ucontext.h>
-#include <unistd.h>
-#include <unwind.h>
-#include <atomic>
-
-// ptrace.h is polluting the namespace. Clean up to avoid conflicts with rtc.
-#if defined(DS)
-#undef DS
-#endif
-
-#include "rtc_base/critical_section.h"
-#include "rtc_base/logging.h"
-#include "rtc_base/strings/string_builder.h"
-
-namespace webrtc {
-
-namespace {
-
-// Maximum stack trace depth we allow before aborting.
-constexpr size_t kMaxStackSize = 100;
-// Signal that will be used to interrupt threads. SIGURG ("Urgent condition on
-// socket") is chosen because Android does not set up a specific handler for
-// this signal.
-constexpr int kSignal = SIGURG;
-
-// Note: This class is only meant for use within this file, and for the
-// simplified use case of a single Wait() and a single Signal(), followed by
-// discarding the object (never reused).
-// This is a replacement of rtc::Event that is async-safe and doesn't use
-// pthread api. This is necessary since signal handlers cannot allocate memory
-// or use pthread api. This class is ported from Chromium.
-class AsyncSafeWaitableEvent {
- public:
- AsyncSafeWaitableEvent() {
- std::atomic_store_explicit(&futex_, 0, std::memory_order_release);
- }
-
- ~AsyncSafeWaitableEvent() {}
-
- // Returns false in the event of an error and errno is set to indicate the
- // cause of the error.
- bool Wait() {
- // futex() can wake up spuriously if this memory address was previously used
- // for a pthread mutex. So, also check the condition.
- while (true) {
- int res = syscall(SYS_futex, &futex_, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0,
- nullptr, nullptr, 0);
- if (std::atomic_load_explicit(&futex_, std::memory_order_acquire) != 0)
- return true;
- if (res != 0)
- return false;
- }
- }
-
- void Signal() {
- std::atomic_store_explicit(&futex_, 1, std::memory_order_release);
- syscall(SYS_futex, &futex_, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1, nullptr,
- nullptr, 0);
- }
-
- private:
- std::atomic<int> futex_;
-};
-
-// Struct to store the arguments to the signal handler.
-struct SignalHandlerOutputState {
- // This event is signalled when signal handler is done executing.
- AsyncSafeWaitableEvent signal_handler_finish_event;
- // Running counter of array index below.
- size_t stack_size_counter = 0;
- // Array storing the stack trace.
- uintptr_t addresses[kMaxStackSize];
-};
-
-// Global lock to ensure only one thread gets interrupted at a time.
-rtc::GlobalLockPod g_signal_handler_lock;
-// Argument passed to the ThreadSignalHandler() from the sampling thread to the
-// sampled (stopped) thread. This value is set just before sending signal to the
-// thread and reset when handler is done.
-SignalHandlerOutputState* volatile g_signal_handler_output_state;
-
-// This function is called iteratively for each stack trace element and stores
-// the element in the array from |unwind_output_state|.
-_Unwind_Reason_Code UnwindBacktrace(struct _Unwind_Context* unwind_context,
- void* unwind_output_state) {
- SignalHandlerOutputState* const output_state =
- static_cast<SignalHandlerOutputState*>(unwind_output_state);
-
- // Avoid overflowing the stack trace array.
- if (output_state->stack_size_counter >= kMaxStackSize)
- return _URC_END_OF_STACK;
-
- // Store the instruction pointer in the array. Subtract 2 since we want to get
- // the call instruction pointer, not the return address which is the
- // instruction after.
- output_state->addresses[output_state->stack_size_counter] =
- _Unwind_GetIP(unwind_context) - 2;
- ++output_state->stack_size_counter;
-
- return _URC_NO_REASON;
-}
-
-// This signal handler is exectued on the interrupted thread.
-void SignalHandler(int signum, siginfo_t* info, void* ptr) {
- _Unwind_Backtrace(&UnwindBacktrace, g_signal_handler_output_state);
- g_signal_handler_output_state->signal_handler_finish_event.Signal();
-}
-
-// Temporarily change the signal handler to a function that records a raw stack
-// trace and interrupt the given tid. This function will block until the output
-// thread stack trace has been stored in |params|. The return value is an error
-// string on failure and null on success.
-const char* CaptureRawStacktrace(int pid,
- int tid,
- SignalHandlerOutputState* params) {
- // This function is under a global lock since we are changing the signal
- // handler and using global state for the output. The lock is to ensure only
- // one thread at a time gets captured. The lock also means we need to be very
- // careful with what statements we put in this function, and we should even
- // avoid logging here.
- struct sigaction act;
- struct sigaction old_act;
- memset(&act, 0, sizeof(act));
- act.sa_sigaction = &SignalHandler;
- act.sa_flags = SA_RESTART | SA_SIGINFO;
- sigemptyset(&act.sa_mask);
-
- rtc::GlobalLockScope ls(&g_signal_handler_lock);
- g_signal_handler_output_state = params;
-
- if (sigaction(kSignal, &act, &old_act) != 0)
- return "Failed to change signal action";
-
- // Interrupt the thread which will execute SignalHandler() on the given
- // thread.
- if (tgkill(pid, tid, kSignal) != 0)
- return "Failed to interrupt thread";
-
- // Wait until the thread is done recording its stack trace.
- if (!params->signal_handler_finish_event.Wait())
- return "Failed to wait for thread to finish stack trace";
-
- // Restore previous signal handler.
- sigaction(kSignal, &old_act, /* old_act= */ nullptr);
-
- return nullptr;
-}
-
-} // namespace
-
-std::vector<StackTraceElement> GetStackTrace(int tid) {
- // Only a thread itself can unwind its stack, so we will interrupt the given
- // tid with a custom signal handler in order to unwind its stack. The stack
- // will be recorded to |params| through the use of the global pointer
- // |g_signal_handler_param|.
- SignalHandlerOutputState params;
-
- const char* error_string = CaptureRawStacktrace(getpid(), tid, ¶ms);
- if (error_string != nullptr) {
- RTC_LOG(LS_ERROR) << error_string << ". tid: " << tid
- << ". errno: " << errno;
- return {};
- }
-
- if (params.stack_size_counter >= kMaxStackSize)
- RTC_LOG(LS_WARNING) << "Stack trace for thread " << tid << " was truncated";
-
- // Translate addresses into symbolic information using dladdr().
- std::vector<StackTraceElement> stack_trace;
- for (size_t i = 0; i < params.stack_size_counter; ++i) {
- const uintptr_t address = params.addresses[i];
-
- Dl_info dl_info = {};
- if (!dladdr(reinterpret_cast<void*>(address), &dl_info)) {
- RTC_LOG(LS_WARNING)
- << "Could not translate address to symbolic information for address "
- << address << " at stack depth " << i;
- continue;
- }
-
- StackTraceElement stack_trace_element;
- stack_trace_element.shared_object_path = dl_info.dli_fname;
- stack_trace_element.relative_address = static_cast<uint32_t>(
- address - reinterpret_cast<uintptr_t>(dl_info.dli_fbase));
- stack_trace_element.symbol_name = dl_info.dli_sname;
-
- stack_trace.push_back(stack_trace_element);
- }
-
- return stack_trace;
-}
-
-std::string StackTraceToString(
- const std::vector<StackTraceElement>& stack_trace) {
- rtc::StringBuilder string_builder;
-
- for (size_t i = 0; i < stack_trace.size(); ++i) {
- const StackTraceElement& stack_trace_element = stack_trace[i];
- string_builder.AppendFormat(
- "#%02zu pc %08x %s", i,
- static_cast<uint32_t>(stack_trace_element.relative_address),
- stack_trace_element.shared_object_path);
- // The symbol name is only available for unstripped .so files.
- if (stack_trace_element.symbol_name != nullptr)
- string_builder.AppendFormat(" %s", stack_trace_element.symbol_name);
-
- string_builder.AppendFormat("\n");
- }
-
- return string_builder.Release();
-}
-
-} // namespace webrtc
diff --git a/sdk/android/native_api/stacktrace/stacktrace.h b/sdk/android/native_api/stacktrace/stacktrace.h
deleted file mode 100644
index 1fbf21b..0000000
--- a/sdk/android/native_api/stacktrace/stacktrace.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2019 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef SDK_ANDROID_NATIVE_API_STACKTRACE_STACKTRACE_H_
-#define SDK_ANDROID_NATIVE_API_STACKTRACE_STACKTRACE_H_
-
-#include <string>
-#include <vector>
-
-namespace webrtc {
-
-struct StackTraceElement {
- // Pathname of shared object (.so file) that contains address.
- const char* shared_object_path;
- // Execution address relative to the .so base address. This matches the
- // addresses you get with "nm", "objdump", and "ndk-stack", as long as the
- // code is compiled with position-independent code. Android requires
- // position-independent code since Lollipop.
- uint32_t relative_address;
- // Name of symbol whose definition overlaps the address. This value is null
- // when symbol names are stripped.
- const char* symbol_name;
-};
-
-// Utility to unwind stack for a given thread on Android ARM devices. This works
-// on top of unwind.h and unwinds native (C++) stack traces only.
-std::vector<StackTraceElement> GetStackTrace(int tid);
-
-// Get a string representation of the stack trace in a format ndk-stack accepts.
-std::string StackTraceToString(
- const std::vector<StackTraceElement>& stack_trace);
-
-} // namespace webrtc
-
-#endif // SDK_ANDROID_NATIVE_API_STACKTRACE_STACKTRACE_H_
diff --git a/sdk/android/native_unittests/stacktrace/stacktrace_unittest.cc b/sdk/android/native_unittests/stacktrace/stacktrace_unittest.cc
deleted file mode 100644
index 4268fda..0000000
--- a/sdk/android/native_unittests/stacktrace/stacktrace_unittest.cc
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright 2019 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "sdk/android/native_api/stacktrace/stacktrace.h"
-#include <dlfcn.h>
-#include <vector>
-#include "absl/memory/memory.h"
-#include "rtc_base/criticalsection.h"
-#include "rtc_base/event.h"
-#include "rtc_base/logging.h"
-#include "rtc_base/platform_thread.h"
-#include "rtc_base/strings/string_builder.h"
-#include "test/gtest.h"
-
-namespace webrtc {
-namespace test {
-
-// Returns the execution address relative to the .so base address. This matches
-// the addresses we get from GetStacktrace().
-uint32_t GetCurrentRelativeExecutionAddress() {
- void* pc = __builtin_return_address(0);
- Dl_info dl_info = {};
- const bool success = dladdr(pc, &dl_info);
- EXPECT_TRUE(success);
- return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(pc) -
- reinterpret_cast<uintptr_t>(dl_info.dli_fbase));
-}
-
-// Returns true if any of the stack trace element is inside the specified
-// region.
-bool StackTraceContainsRange(const std::vector<StackTraceElement>& stack_trace,
- uintptr_t pc_low,
- uintptr_t pc_high) {
- for (const StackTraceElement& stack_trace_element : stack_trace) {
- if (pc_low <= stack_trace_element.relative_address &&
- pc_high >= stack_trace_element.relative_address) {
- return true;
- }
- }
- return false;
-}
-
-class DeadlockInterface {
- public:
- virtual ~DeadlockInterface() {}
-
- // This function should deadlock until Release() is called.
- virtual void Deadlock() = 0;
-
- // This function should release the thread stuck in Deadlock().
- virtual void Release() = 0;
-};
-
-struct ThreadParams {
- volatile int tid;
- // Signaled when the deadlock region is entered.
- rtc::Event deadlock_start_event;
- DeadlockInterface* volatile deadlock_impl;
- // Defines an address range within the deadlock will occur.
- volatile uint32_t deadlock_region_start_address;
- volatile uint32_t deadlock_region_end_address;
- // Signaled when the deadlock is done.
- rtc::Event deadlock_done_event;
-};
-
-class RtcEventDeadlock : public DeadlockInterface {
- private:
- void Deadlock() override { event.Wait(rtc::Event::kForever); }
- void Release() override { event.Set(); }
-
- rtc::Event event;
-};
-
-class RtcCriticalSectionDeadlock : public DeadlockInterface {
- public:
- RtcCriticalSectionDeadlock()
- : critscope_(absl::make_unique<rtc::CritScope>(&crit_)) {}
-
- private:
- void Deadlock() override { rtc::CritScope lock(&crit_); }
-
- void Release() override { critscope_.reset(); }
-
- rtc::CriticalSection crit_;
- std::unique_ptr<rtc::CritScope> critscope_;
-};
-
-class SpinDeadlock : public DeadlockInterface {
- public:
- SpinDeadlock() : is_deadlocked_(true) {}
-
- private:
- void Deadlock() override {
- while (is_deadlocked_) {
- }
- }
-
- void Release() override { is_deadlocked_ = false; }
-
- std::atomic<bool> is_deadlocked_;
-};
-
-class SleepDeadlock : public DeadlockInterface {
- private:
- void Deadlock() override { sleep(1000000); }
-
- void Release() override {
- // The interrupt itself will break free from the sleep.
- }
-};
-
-// This is the function that is exectued by the thread that will deadlock and
-// have its stacktrace captured.
-void ThreadFunction(void* void_params) {
- ThreadParams* params = static_cast<ThreadParams*>(void_params);
- params->tid = gettid();
-
- params->deadlock_region_start_address = GetCurrentRelativeExecutionAddress();
- params->deadlock_start_event.Set();
- params->deadlock_impl->Deadlock();
- params->deadlock_region_end_address = GetCurrentRelativeExecutionAddress();
-
- params->deadlock_done_event.Set();
-}
-
-void TestStacktrace(std::unique_ptr<DeadlockInterface> deadlock_impl) {
- // Set params that will be sent to other thread.
- ThreadParams params;
- params.deadlock_impl = deadlock_impl.get();
-
- // Spawn thread.
- rtc::PlatformThread thread(&ThreadFunction, ¶ms, "StacktraceTest");
- thread.Start();
-
- // Wait until the thread has entered the deadlock region.
- params.deadlock_start_event.Wait(rtc::Event::kForever);
-
- // Acquire the stack trace of the thread which should now be deadlocking.
- std::vector<StackTraceElement> stack_trace = GetStackTrace(params.tid);
-
- // Release the deadlock so that the thread can continue.
- deadlock_impl->Release();
-
- // Wait until the thread has left the deadlock.
- params.deadlock_done_event.Wait(rtc::Event::kForever);
-
- // Assert that the stack trace contains the deadlock region.
- EXPECT_TRUE(StackTraceContainsRange(stack_trace,
- params.deadlock_region_start_address,
- params.deadlock_region_end_address))
- << "Deadlock region: ["
- << rtc::ToHex(params.deadlock_region_start_address) << ", "
- << rtc::ToHex(params.deadlock_region_end_address)
- << "] not contained in: " << StackTraceToString(stack_trace);
-
- thread.Stop();
-}
-
-TEST(Stacktrace, TestSpinLock) {
- TestStacktrace(absl::make_unique<SpinDeadlock>());
-}
-
-TEST(Stacktrace, TestSleep) {
- TestStacktrace(absl::make_unique<SleepDeadlock>());
-}
-
-// Stack traces originating from kernel space does not include user space stack
-// traces for ARM 32.
-#ifdef WEBRTC_ARCH_ARM64
-TEST(Stacktrace, TestRtcEvent) {
- TestStacktrace(absl::make_unique<RtcEventDeadlock>());
-}
-
-TEST(Stacktrace, TestRtcCriticalSection) {
- TestStacktrace(absl::make_unique<RtcCriticalSectionDeadlock>());
-}
-#endif
-
-} // namespace test
-} // namespace webrtc