Log RunResponse.failure_detail in the client if any; relay them from spawn failures

This behavior is useful for easily testing FailureDetail-related behavior.

---

Detailed failures that occur during spawn evaluations are now propagated
to the gRPC interface and delivered in the final RunResponse message for
"build" invocations.

RELNOTES: None.
PiperOrigin-RevId: 300828765
diff --git a/src/main/cpp/blaze.cc b/src/main/cpp/blaze.cc
index b9665e0..8210b86 100644
--- a/src/main/cpp/blaze.cc
+++ b/src/main/cpp/blaze.cc
@@ -2114,6 +2114,11 @@
     ExecuteRunRequest(blaze_util::Path(request.argv(0)), argv);
   }
 
+  if (final_response.has_failure_detail()) {
+    BAZEL_LOG(INFO)
+        << "failure_detail: " << final_response.failure_detail().DebugString();
+  }
+
   // We'll exit with exit code SIGPIPE on Unixes due to PropagateSignalOnExit()
   return pipe_broken
       ? blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR
diff --git a/src/main/java/com/google/devtools/build/lib/exec/SpawnExecException.java b/src/main/java/com/google/devtools/build/lib/exec/SpawnExecException.java
index 091e0df..15620d6 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/SpawnExecException.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/SpawnExecException.java
@@ -76,8 +76,14 @@
   /** Return exit code depending on the spawn result. */
   private DetailedExitCode getDetailedExitCode() {
     if (result.status().isConsideredUserError()) {
+      if (result.failureDetail() != null) {
+        return DetailedExitCode.of(ExitCode.BUILD_FAILURE, result.failureDetail());
+      }
       return null;
     }
+    if (result.failureDetail() != null) {
+      return DetailedExitCode.of(ExitCode.REMOTE_ERROR, result.failureDetail());
+    }
     return DetailedExitCode.justExitCode(ExitCode.REMOTE_ERROR);
   }
 }