diff options
-rw-r--r-- | libbacktrace/BacktraceCurrent.cpp | 11 | ||||
-rw-r--r-- | libbacktrace/BacktraceCurrent.h | 3 | ||||
-rw-r--r-- | libbacktrace/UnwindCurrent.cpp | 39 | ||||
-rw-r--r-- | libbacktrace/backtrace_test.cpp | 18 |
4 files changed, 54 insertions, 17 deletions
diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp index b7190e2..fd1f4da 100644 --- a/libbacktrace/BacktraceCurrent.cpp +++ b/libbacktrace/BacktraceCurrent.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#define _GNU_SOURCE 1 #include <errno.h> #include <stdint.h> #include <string.h> @@ -73,6 +74,16 @@ bool BacktraceCurrent::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { return UnwindFromContext(num_ignore_frames, nullptr); } +bool BacktraceCurrent::DiscardFrame(const backtrace_frame_data_t& frame) { + if (BacktraceMap::IsValid(frame.map)) { + const std::string library = basename(frame.map.name.c_str()); + if (library == "libunwind.so" || library == "libbacktrace.so") { + return true; + } + } + return false; +} + static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER; static void SignalHandler(int, siginfo_t*, void* sigcontext) { diff --git a/libbacktrace/BacktraceCurrent.h b/libbacktrace/BacktraceCurrent.h index 81ea81d..8aad36d 100644 --- a/libbacktrace/BacktraceCurrent.h +++ b/libbacktrace/BacktraceCurrent.h @@ -46,6 +46,9 @@ public: bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) override; +protected: + bool DiscardFrame(const backtrace_frame_data_t& frame); + private: bool UnwindThread(size_t num_ignore_frames); diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp index 12e2890..67e583f 100644 --- a/libbacktrace/UnwindCurrent.cpp +++ b/libbacktrace/UnwindCurrent.cpp @@ -99,25 +99,30 @@ bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucon break; } - if (num_ignore_frames == 0) { - frames_.resize(num_frames+1); - backtrace_frame_data_t* frame = &frames_.at(num_frames); - frame->num = num_frames; - frame->pc = static_cast<uintptr_t>(pc); - frame->sp = static_cast<uintptr_t>(sp); - frame->stack_size = 0; + frames_.resize(num_frames+1); + backtrace_frame_data_t* frame = &frames_.at(num_frames); + frame->num = num_frames; + frame->pc = static_cast<uintptr_t>(pc); + frame->sp = static_cast<uintptr_t>(sp); + frame->stack_size = 0; - if (num_frames > 0) { - // Set the stack size for the previous frame. - backtrace_frame_data_t* prev = &frames_.at(num_frames-1); - prev->stack_size = frame->sp - prev->sp; + FillInMap(frame->pc, &frame->map); + // Check to see if we should skip this frame because it's coming + // from within the library, and we are doing a local unwind. + if (ucontext != nullptr || num_frames != 0 || !DiscardFrame(*frame)) { + if (num_ignore_frames == 0) { + // GetFunctionName is an expensive call, only do it if we are + // keeping the frame. + frame->func_name = GetFunctionName(frame->pc, &frame->func_offset); + if (num_frames > 0) { + // Set the stack size for the previous frame. + backtrace_frame_data_t* prev = &frames_.at(num_frames-1); + prev->stack_size = frame->sp - prev->sp; + } + num_frames++; + } else { + num_ignore_frames--; } - - frame->func_name = GetFunctionName(frame->pc, &frame->func_offset); - FillInMap(frame->pc, &frame->map); - num_frames++; - } else { - num_ignore_frames--; } ret = unw_step (cursor.get()); } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES); diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp index d408856..5de80b1 100644 --- a/libbacktrace/backtrace_test.cpp +++ b/libbacktrace/backtrace_test.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#define _GNU_SOURCE 1 #include <dirent.h> #include <errno.h> #include <inttypes.h> @@ -200,6 +201,23 @@ bool WaitForNonZero(int32_t* value, uint64_t seconds) { return false; } +TEST(libbacktrace, local_no_unwind_frames) { + // Verify that a local unwind does not include any frames within + // libunwind or libbacktrace. + std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), getpid())); + ASSERT_TRUE(backtrace->Unwind(0)); + + ASSERT_TRUE(backtrace->NumFrames() != 0); + 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()); + } + break; + } +} + TEST(libbacktrace, local_trace) { ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelBacktrace, nullptr), 0); } |