diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp index 711a12a6c..e087b2e15 100644 --- a/libbacktrace/UnwindStack.cpp +++ b/libbacktrace/UnwindStack.cpp @@ -163,6 +163,9 @@ bool UnwindStackCurrent::UnwindFromContext(size_t num_ignore_frames, void* ucont } std::vector skip_names{"libunwindstack.so", "libbacktrace.so"}; + if (!skip_frames_) { + skip_names.clear(); + } return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, &skip_names, &error_); } diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp index aab6db9de..1e3d37981 100644 --- a/libbacktrace/backtrace_test.cpp +++ b/libbacktrace/backtrace_test.cpp @@ -69,6 +69,9 @@ // Number of simultaneous threads running in our forked process. #define NUM_PTRACE_THREADS 5 +// The list of shared libaries that make up the backtrace library. +static std::vector kBacktraceLibs{"libunwindstack.so", "libbacktrace.so"}; + struct thread_t { pid_t tid; int32_t state; @@ -256,16 +259,49 @@ TEST(libbacktrace, local_no_unwind_frames) { VERIFY_NO_ERROR(backtrace->GetError().error_code); ASSERT_TRUE(backtrace->NumFrames() != 0); + // None of the frames should be in the backtrace libraries. for (const auto& frame : *backtrace ) { if (BacktraceMap::IsValid(frame.map)) { const std::string name = basename(frame.map.name.c_str()); - ASSERT_TRUE(name != "libunwind.so" && name != "libbacktrace.so") - << DumpFrames(backtrace.get()); + for (const auto& lib : kBacktraceLibs) { + ASSERT_TRUE(name != lib) << DumpFrames(backtrace.get()); + } } - break; } } +TEST(libbacktrace, local_unwind_frames) { + // Verify that a local unwind with the skip frames disabled does include + // frames within the backtrace libraries. + std::unique_ptr backtrace(Backtrace::Create(getpid(), getpid())); + ASSERT_TRUE(backtrace.get() != nullptr); + backtrace->SetSkipFrames(false); + ASSERT_TRUE(backtrace->Unwind(0)); + VERIFY_NO_ERROR(backtrace->GetError().error_code); + + ASSERT_TRUE(backtrace->NumFrames() != 0); + size_t first_frame_non_backtrace_lib = 0; + for (const auto& frame : *backtrace) { + if (BacktraceMap::IsValid(frame.map)) { + const std::string name = basename(frame.map.name.c_str()); + bool found = false; + for (const auto& lib : kBacktraceLibs) { + if (name == lib) { + found = true; + break; + } + } + if (!found) { + first_frame_non_backtrace_lib = frame.num; + break; + } + } + } + + ASSERT_NE(0U, first_frame_non_backtrace_lib) << "No frames found in backtrace libraries:\n" + << DumpFrames(backtrace.get()); +} + TEST(libbacktrace, local_trace) { ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelBacktrace, nullptr), 0); } diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h index a0882079e..735a2f36e 100644 --- a/libbacktrace/include/backtrace/Backtrace.h +++ b/libbacktrace/include/backtrace/Backtrace.h @@ -204,6 +204,9 @@ class Backtrace { std::string GetErrorString(BacktraceUnwindError error); + // Set whether to skip frames in libbacktrace/libunwindstack when doing a local unwind. + void SetSkipFrames(bool skip_frames) { skip_frames_ = skip_frames; } + protected: Backtrace(pid_t pid, pid_t tid, BacktraceMap* map); @@ -223,6 +226,9 @@ class Backtrace { std::vector frames_; + // Skip frames in libbacktrace/libunwindstack when doing a local unwind. + bool skip_frames_ = true; + BacktraceUnwindError error_; };