blob: cad8bd7f98f5b27f2d7333104a6a442657224723 [file] [log] [blame]
#include "compartment.h"
#include <cheri.hh>
#include <debug.hh>
#include <priv/riscv.h>
#include <simulator.h>
using DebugErrorHandler = ConditionalDebug<
#ifdef NDEBUG
false
#else
true
#endif
,
"Error handler">;
/**
* A error handler that reports unexpected traps and calls the scheduler to
* request that the simulator exit with exit code 1 (FAILURE).
*
* This is useful because the default behaviour in the absence of an error
* handler is to unwind the trusted stack and exit the thread when the top of
* the stack is reached. If all threads exit then the scheduler will exit the
* simulation with SUCCESS, which might mask errors.
*
* We attempt to detect the trap that occurs when a thread returns from its
* entry point function and do not halt the simulation as this is considered
* normal.
*
* Unwinds caused by errors in called compartments are also detected and are not
* treated as errors -- instead we resume execution at the call point with a
* return value of -1 as though this handler is not present.
*
* On non-simulation platforms this error handler reverts to the default force
* unwind behaviour.
*
* If NDEBUG is not defined then errors and thread exits will be logged.
*
* To use this simply include this file in your compartment's c / cc file.
*/
extern "C" ErrorRecoveryBehaviour
compartment_error_handler(ErrorState *frame, size_t mcause, size_t mtval)
{
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);
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 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;
}