Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit af16967e authored by Christopher Ferris's avatar Christopher Ferris
Browse files

Method to avoid skipping frames for local unwinds.

In cases where there might be a crash in the unwind library itself,
we need a method to avoid skipping these frames or we won't be able
to see the actual crash.

Added unit test for this behavior.

Bug: 74121887

Test: Ran unit tests on host and target.
Change-Id: I45825020c174016af39dd8ffdc67acb72a24ad4d
(cherry picked from commit 458f4e72)
parent 677bed57
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -163,6 +163,9 @@ bool UnwindStackCurrent::UnwindFromContext(size_t num_ignore_frames, void* ucont
  }

  std::vector<std::string> 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_);
}

+39 −3
Original line number Diff line number Diff line
@@ -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<std::string> kBacktraceLibs{"libunwindstack.so", "libbacktrace.so"};

struct thread_t {
  pid_t tid;
  int32_t state;
@@ -256,15 +259,48 @@ 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());
      }
    }
  }
}

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(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);
+6 −0
Original line number Diff line number Diff line
@@ -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<backtrace_frame_data_t> frames_;

  // Skip frames in libbacktrace/libunwindstack when doing a local unwind.
  bool skip_frames_ = true;

  BacktraceUnwindError error_;
};