Introduce SetFirstChanceHandler with more strict signature

Eventually, I want to remove the current version of
SetFirstChanceHandler. That is why I changed the name of the current
callback type to FirstChanceHandlerDeprecated.

I also made sure that it is not possible to have two different
FirstChanceHandlers set at the same time.

This is the first of a set of CLs to clean up the API between Chrome,
BreakPad, and V8. See more information in the tracking bug.

R=mark@chromium.org

Bug: chromium:921971
Change-Id: Ia8c2fd9bd875c36dd7ae8bb4a02e538556bc67a1
Reviewed-on: https://chromium-review.googlesource.com/c/1411776
Reviewed-by: Mark Mentovai <mark@chromium.org>
diff --git a/src/client/linux/handler/exception_handler.cc b/src/client/linux/handler/exception_handler.cc
index b895f6d..0d7cd9c 100644
--- a/src/client/linux/handler/exception_handler.cc
+++ b/src/client/linux/handler/exception_handler.cc
@@ -213,6 +213,7 @@
 ExceptionHandler::CrashContext g_crash_context_;
 
 FirstChanceHandler g_first_chance_handler_ = nullptr;
+FirstChanceHandlerDeprecated g_first_chance_handler_deprecated_ = nullptr;
 }  // namespace
 
 // Runs before crashing: normal context.
@@ -338,6 +339,11 @@
     return;
   }
 
+  if (g_first_chance_handler_deprecated_ != nullptr &&
+      g_first_chance_handler_deprecated_(sig, info, uc)) {
+    return;
+  }
+
   // All the exception signals are blocked at this point.
   pthread_mutex_lock(&g_handler_stack_mutex_);
 
@@ -791,7 +797,13 @@
 }
 
 void SetFirstChanceExceptionHandler(FirstChanceHandler callback) {
+  g_first_chance_handler_deprecated_ = nullptr;
   g_first_chance_handler_ = callback;
 }
 
+void SetFirstChanceExceptionHandler(FirstChanceHandlerDeprecated callback) {
+  g_first_chance_handler_ = nullptr;
+  g_first_chance_handler_deprecated_ = callback;
+}
+
 }  // namespace google_breakpad
diff --git a/src/client/linux/handler/exception_handler.h b/src/client/linux/handler/exception_handler.h
index 1695a2b..1ddeac8 100644
--- a/src/client/linux/handler/exception_handler.h
+++ b/src/client/linux/handler/exception_handler.h
@@ -273,10 +273,14 @@
   AppMemoryList app_memory_list_;
 };
 
-
-typedef bool (*FirstChanceHandler)(int, void*, void*);
+typedef bool (*FirstChanceHandler)(int, siginfo_t*, void*);
 void SetFirstChanceExceptionHandler(FirstChanceHandler callback);
 
+typedef bool (*FirstChanceHandlerDeprecated)(int, void*, void*);
+// Deprecated. Use SetFirstChanceExceptionHandler(FirstChanceHandler callback)
+// instead.
+void SetFirstChanceExceptionHandler(FirstChanceHandlerDeprecated callback);
+
 }  // namespace google_breakpad
 
 #endif  // CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_
diff --git a/src/client/linux/handler/exception_handler_unittest.cc b/src/client/linux/handler/exception_handler_unittest.cc
index 329d014..2e4eb09 100644
--- a/src/client/linux/handler/exception_handler_unittest.cc
+++ b/src/client/linux/handler/exception_handler_unittest.cc
@@ -528,9 +528,30 @@
 
 namespace {
 const int kSimpleFirstChanceReturnStatus = 42;
-bool SimpleFirstChanceHandler(int, void*, void*) {
+bool SimpleFirstChanceHandlerDeprecated(int, void*, void*) {
   _exit(kSimpleFirstChanceReturnStatus);
 }
+
+bool SimpleFirstChanceHandler(int, siginfo_t*, void*) {
+  _exit(kSimpleFirstChanceReturnStatus);
+}
+}
+
+TEST(ExceptionHandlerTest, FirstChanceHandlerRunsDeprecated) {
+  AutoTempDir temp_dir;
+
+  const pid_t child = fork();
+  if (child == 0) {
+    ExceptionHandler handler(
+        MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1);
+    google_breakpad::SetFirstChanceExceptionHandler(
+        SimpleFirstChanceHandlerDeprecated);
+    DoNullPointerDereference();
+  }
+  int status;
+  ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1);
+  ASSERT_TRUE(WIFEXITED(status));
+  ASSERT_EQ(kSimpleFirstChanceReturnStatus, WEXITSTATUS(status));
 }
 
 TEST(ExceptionHandlerTest, FirstChanceHandlerRuns) {