Add ability to unwind stack for the current thread

Bug: webrtc:10308
Change-Id: Ia82cb7512524bede8da69bbc747ece6e718733ab
Reviewed-on: https://webrtc-review.googlesource.com/c/124993
Reviewed-by: Magnus Jedvert <magjed@webrtc.org>
Commit-Queue: Karl Wiberg <kwiberg@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26945}
This commit is contained in:
Karl Wiberg 2019-02-28 17:06:54 +01:00 committed by Commit Bot
parent 8b8d01ada3
commit c130d42aab
3 changed files with 46 additions and 20 deletions

View File

@ -164,26 +164,9 @@ const char* CaptureRawStacktrace(int pid,
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, &params);
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().
// Translate addresses into symbolic information using dladdr().
std::vector<StackTraceElement> FormatStackTrace(
const SignalHandlerOutputState& params) {
std::vector<StackTraceElement> stack_trace;
for (size_t i = 0; i < params.stack_size_counter; ++i) {
const uintptr_t address = params.addresses[i];
@ -208,6 +191,36 @@ std::vector<StackTraceElement> GetStackTrace(int tid) {
return stack_trace;
}
} // 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, &params);
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";
}
return FormatStackTrace(params);
}
std::vector<StackTraceElement> GetStackTrace() {
SignalHandlerOutputState params;
_Unwind_Backtrace(&UnwindBacktrace, &params);
if (params.stack_size_counter >= kMaxStackSize) {
RTC_LOG(LS_WARNING) << "Stack trace was truncated";
}
return FormatStackTrace(params);
}
std::string StackTraceToString(
const std::vector<StackTraceElement>& stack_trace) {
rtc::StringBuilder string_builder;

View File

@ -33,6 +33,9 @@ struct StackTraceElement {
// on top of unwind.h and unwinds native (C++) stack traces only.
std::vector<StackTraceElement> GetStackTrace(int tid);
// Unwind the stack of the current thread.
std::vector<StackTraceElement> GetStackTrace();
// Get a string representation of the stack trace in a format ndk-stack accepts.
std::string StackTraceToString(
const std::vector<StackTraceElement>& stack_trace);

View File

@ -163,6 +163,16 @@ void TestStacktrace(std::unique_ptr<DeadlockInterface> deadlock_impl) {
thread.Stop();
}
TEST(Stacktrace, TestCurrentThread) {
const uint32_t start_addr = GetCurrentRelativeExecutionAddress();
const std::vector<StackTraceElement> stack_trace = GetStackTrace();
const uint32_t end_addr = GetCurrentRelativeExecutionAddress();
EXPECT_TRUE(StackTraceContainsRange(stack_trace, start_addr, end_addr))
<< "Caller region: [" << rtc::ToHex(start_addr) << ", "
<< rtc::ToHex(end_addr)
<< "] not contained in: " << StackTraceToString(stack_trace);
}
TEST(Stacktrace, TestSpinLock) {
TestStacktrace(absl::make_unique<SpinDeadlock>());
}