fail-simulator-on-error: no special case for exit

Now that the initial cra for threads is a sentry to a graceful exit and
not nullptr, there's no need to detect and notch out exceptions arising
from thread exits.

Co-authored-by: Robert Norton <robert.norton@microsoft.com>
diff --git a/sdk/include/fail-simulator-on-error.h b/sdk/include/fail-simulator-on-error.h
index d26dceb..cad8bd7 100644
--- a/sdk/include/fail-simulator-on-error.h
+++ b/sdk/include/fail-simulator-on-error.h
@@ -42,56 +42,36 @@
 {
 	if (mcause == priv::MCAUSE_CHERI)
 	{
+		// An unexpected error -- log it and end the simulation with error.
+		// Note: handle CZR differently as `get_register_value` will return a
+		// nullptr which we cannot dereference.
+
 		auto [exceptionCode, registerNumber] =
 		  CHERI::extract_cheri_mtval(mtval);
-		// The thread entry point is called with a NULL return address so the
-		// cret at the end of the entry point function will trap if it is
-		// reached. We don't want to treat this as an error but thankfully we
-		// detect it quite specifically by checking for all of:
-		// 1) CHERI cause is tag violation
-		// 2) faulting register is CRA
-		// 3) value of CRA is NULL
-		// 4) we've reached the top of the thread's stack
-		CHERI::Capability stackCapability{
-		  frame->get_register_value<CHERI::RegisterNumber::CSP>()};
-		CHERI::Capability returnCapability{
-		  frame->get_register_value<CHERI::RegisterNumber::CRA>()};
-		// The top of the stack is 16 bytes above the stack pointer on entry,
-		// to provide space for unwind lists and so on.
-		if (registerNumber == CHERI::RegisterNumber::CRA &&
-		    returnCapability.address() == 0 &&
-		    exceptionCode == CHERI::CauseCode::TagViolation &&
-		    (stackCapability.top() - 16) == stackCapability.address())
-		{
-			// looks like thread exit -- just log it then ForceUnwind
-			DebugErrorHandler::log(
-			  "Thread exit CSP={}, PCC={}", stackCapability, frame->pcc);
-		}
-		else
-		{
-			// An unexpected error -- log it and end the simulation
-			// with error.  Note: handle CZR differently as
-			// `get_register_value` will return a nullptr which we
-			// cannot dereference.
-			DebugErrorHandler::log(
-			  "{} error at {} (return address: {}), with capability register "
-			  "{}: {}",
-			  exceptionCode,
-			  frame->pcc,
-			  frame->get_register_value<CHERI::RegisterNumber::CRA>(),
-			  registerNumber,
-			  registerNumber == CHERI::RegisterNumber::CZR
-			    ? nullptr
-			    : *frame->get_register_value(registerNumber));
-			simulation_exit(1);
-		}
+
+		DebugErrorHandler::log(
+		  "{} error at {} (return address: {}), with capability register "
+		  "{}: {}",
+		  exceptionCode,
+		  frame->pcc,
+		  frame->get_register_value<CHERI::RegisterNumber::CRA>(),
+		  registerNumber,
+		  registerNumber == CHERI::RegisterNumber::CZR
+		    ? nullptr
+		    : *frame->get_register_value(registerNumber));
 	}
 	else
 	{
 		// other error (e.g. __builtin_trap causes ReservedInstruciton)
 		// log and end simulation with error.
 		DebugErrorHandler::log("Unhandled error {} at {}", mcause, frame->pcc);
-		simulation_exit(1);
 	}
+
+	simulation_exit(1);
+	/*
+	 * simulation_exit may fail (say, we're not on a simulator or there isn't
+	 * enough stack space to invoke the function.  In that case, just fall back
+	 * to forcibly unwinding.
+	 */
 	return ErrorRecoveryBehaviour::ForceUnwind;
 }