Add get initial regs to ThreadUnwinder. am: 875fd55938

Original change: https://android-review.googlesource.com/c/platform/system/unwinding/+/1981166

Change-Id: Ic47772da5559dacd67874608ae95bcc3fd2fd350
diff --git a/libunwindstack/ThreadUnwinder.cpp b/libunwindstack/ThreadUnwinder.cpp
index b649491..9a8a0a6 100644
--- a/libunwindstack/ThreadUnwinder.cpp
+++ b/libunwindstack/ThreadUnwinder.cpp
@@ -145,7 +145,7 @@
   return nullptr;
 }
 
-void ThreadUnwinder::UnwindWithSignal(int signal, pid_t tid,
+void ThreadUnwinder::UnwindWithSignal(int signal, pid_t tid, std::unique_ptr<Regs>* initial_regs,
                                       const std::vector<std::string>* initial_map_names_to_skip,
                                       const std::vector<std::string>* map_suffixes_to_ignore) {
   ClearErrors();
@@ -164,6 +164,9 @@
   }
 
   std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::CurrentArch(), entry->GetUcontext()));
+  if (initial_regs != nullptr) {
+    initial_regs->reset(regs->Clone());
+  }
   SetRegs(regs.get());
   UnwinderFromPid::Unwind(initial_map_names_to_skip, map_suffixes_to_ignore);
 
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index d87e55c..e21e91d 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -185,7 +185,7 @@
 
   void Unwind(const std::vector<std::string>*, const std::vector<std::string>*) override {}
 
-  void UnwindWithSignal(int signal, pid_t tid,
+  void UnwindWithSignal(int signal, pid_t tid, std::unique_ptr<Regs>* initial_regs = nullptr,
                         const std::vector<std::string>* initial_map_names_to_skip = nullptr,
                         const std::vector<std::string>* map_suffixes_to_ignore = nullptr);
 
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index 1996992..80f931b 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -467,8 +467,8 @@
   size_t frames[kNumConcurrentThreads];
   for (size_t i = 0; i < kNumConcurrentThreads; i++) {
     std::thread* thread = new std::thread([i, &frames, &maps, &process_memory, &wait]() {
-      while (wait)
-        ;
+      while (wait) {
+      }
       std::unique_ptr<Regs> regs(Regs::CreateFromLocal());
       RegsGetLocal(regs.get());
 
@@ -495,8 +495,8 @@
     OuterFunction(TEST_TYPE_LOCAL_WAIT_FOR_FINISH);
   });
 
-  while (tid.load() == 0)
-    ;
+  while (tid.load() == 0) {
+  }
 
   ThreadUnwinder unwinder(512);
   ASSERT_TRUE(unwinder.Init());
@@ -507,6 +507,34 @@
   thread.join();
 }
 
+TEST_F(UnwindTest, thread_unwind_copy_regs) {
+  ResetGlobals();
+
+  std::atomic_int tid(0);
+  std::thread thread([&tid]() {
+    tid = android::base::GetThreadId();
+    OuterFunction(TEST_TYPE_LOCAL_WAIT_FOR_FINISH);
+  });
+
+  while (tid.load() == 0) {
+  }
+
+  ThreadUnwinder unwinder(512);
+  ASSERT_TRUE(unwinder.Init());
+  std::unique_ptr<Regs> initial_regs;
+  unwinder.UnwindWithSignal(SIGRTMIN, tid, &initial_regs);
+  ASSERT_TRUE(initial_regs != nullptr);
+  // Verify the initial registers match the first frame pc/sp.
+  ASSERT_TRUE(unwinder.NumFrames() != 0);
+  auto initial_frame = unwinder.frames()[0];
+  ASSERT_EQ(initial_regs->pc(), initial_frame.pc);
+  ASSERT_EQ(initial_regs->sp(), initial_frame.sp);
+  VerifyUnwindFrames(&unwinder, kFunctionOrder);
+
+  g_finish = true;
+  thread.join();
+}
+
 TEST_F(UnwindTest, thread_unwind_with_external_maps) {
   ResetGlobals();
 
@@ -516,8 +544,8 @@
     OuterFunction(TEST_TYPE_LOCAL_WAIT_FOR_FINISH);
   });
 
-  while (tid.load() == 0)
-    ;
+  while (tid.load() == 0) {
+  }
 
   LocalMaps maps;
   ASSERT_TRUE(maps.Parse());
@@ -546,8 +574,8 @@
                                        std::atomic_bool& start_unwinding,
                                        std::atomic_int& unwinders) {
   return new std::thread([&tid, &unwinder, &start_unwinding, &unwinders]() {
-    while (!start_unwinding.load())
-      ;
+    while (!start_unwinding.load()) {
+    }
 
     ThreadUnwinder thread_unwinder(512, &unwinder);
     // Allow the unwind to timeout since this will be doing multiple
@@ -573,8 +601,8 @@
     OuterFunction(TEST_TYPE_LOCAL_WAIT_FOR_FINISH);
   });
 
-  while (g_waiters.load() != 1)
-    ;
+  while (g_waiters.load() != 1) {
+  }
 
   ThreadUnwinder unwinder(512);
   ASSERT_TRUE(unwinder.Init());
@@ -587,8 +615,8 @@
   }
 
   start_unwinding = true;
-  while (unwinders.load() != kNumThreads)
-    ;
+  while (unwinders.load() != kNumThreads) {
+  }
 
   for (auto* thread : threads) {
     thread->join();
@@ -613,8 +641,8 @@
     threads.push_back(thread);
   }
 
-  while (g_waiters.load() != kNumThreads)
-    ;
+  while (g_waiters.load() != kNumThreads) {
+  }
 
   ThreadUnwinder unwinder(512);
   ASSERT_TRUE(unwinder.Init());
@@ -627,8 +655,8 @@
   }
 
   start_unwinding = true;
-  while (unwinders.load() != kNumThreads)
-    ;
+  while (unwinders.load() != kNumThreads) {
+  }
 
   for (auto* thread : unwinder_threads) {
     thread->join();
@@ -663,8 +691,8 @@
     threads.push_back(thread);
   }
 
-  while (g_waiters.load() != kNumThreads)
-    ;
+  while (g_waiters.load() != kNumThreads) {
+  }
 
   ThreadUnwinder unwinder(512, &maps);
   ASSERT_TRUE(unwinder.Init());
@@ -677,8 +705,8 @@
   }
 
   start_unwinding = true;
-  while (unwinders.load() != kNumThreads)
-    ;
+  while (unwinders.load() != kNumThreads) {
+  }
 
   for (auto* thread : unwinder_threads) {
     thread->join();