Add support for user-specified exception handlers
This commit is contained in:
parent
e43d368fbc
commit
8778d8c5d6
@ -110,3 +110,13 @@ Result ERRF_ThrowResult(Result failure);
|
||||
* on development units/patched ErrDisp.
|
||||
*/
|
||||
Result ERRF_ThrowResultWithMessage(Result failure, const char* message);
|
||||
|
||||
/**
|
||||
* @brief Handles an exception using ErrDisp.
|
||||
* @param excep Exception information
|
||||
* @param regs CPU registers
|
||||
*
|
||||
* You might want to clear ENVINFO's bit0 to be able to see any debugging information.
|
||||
* @sa threadOnException
|
||||
*/
|
||||
void ERRF_ExceptionHandler(ERRF_ExceptionInfo* excep, CpuRegisters* regs) __attribute__((noreturn));
|
||||
|
@ -7,10 +7,23 @@
|
||||
#include <3ds/result.h>
|
||||
#include <3ds/synchronization.h>
|
||||
#include <3ds/svc.h>
|
||||
#include <3ds/errf.h>
|
||||
|
||||
/// Makes the exception handler reuse the stack of the faulting thread as-is
|
||||
#define RUN_HANDLER_ON_FAULTING_STACK ((void*)1)
|
||||
|
||||
/// Makes the exception handler push the exception data on its stack
|
||||
#define WRITE_DATA_TO_HANDLER_STACK NULL
|
||||
|
||||
/// Makes the exception handler push the exception data on the stack of the faulting thread
|
||||
#define WRITE_DATA_TO_FAULTING_STACK ((ERRF_ExceptionData*)1)
|
||||
|
||||
/// libctru thread handle type
|
||||
typedef struct Thread_tag* Thread;
|
||||
|
||||
/// Exception handler type, necessarily an ARM function that does not return.
|
||||
typedef void (*ExceptionHandler)(ERRF_ExceptionInfo* excep, CpuRegisters* regs);
|
||||
|
||||
/**
|
||||
* @brief Creates a new libctru thread.
|
||||
* @param entrypoint The function that will be called first upon thread creation
|
||||
@ -82,3 +95,26 @@ Thread threadGetCurrent(void);
|
||||
* @param rc Exit code
|
||||
*/
|
||||
void threadExit(int rc) __attribute__((noreturn));
|
||||
|
||||
/**
|
||||
* @brief Sets the exception handler for the current thread. Called from the main thread, this sets the default handler.
|
||||
* @param handler The exception handler, necessarily an ARM function that does not return
|
||||
* @param stack_top A pointer to the top of the stack that will be used by the handler. See also @ref RUN_HANDLER_ON_FAULTING_STACK
|
||||
* @param exception_data A pointer to the buffer that will contain the exception data.
|
||||
See also @ref WRITE_DATA_TO_HANDLER_STACK and @ref WRITE_DATA_TO_FAULTING_STACK
|
||||
*
|
||||
* To have CPU exceptions reported through this mechanism, it is normally necessary that UNITINFO is set to a non-zero value when Kernel11 starts,
|
||||
* and this mechanism is also controlled by @ref svcKernelSetState type 6, see 3dbrew.
|
||||
*
|
||||
* VFP exceptions are always reported this way even if the process is being debugged using the debug SVCs.
|
||||
*
|
||||
* The current thread need not be a libctru thread.
|
||||
*/
|
||||
static inline void threadOnException(ExceptionHandler handler, void* stack_top, ERRF_ExceptionData* exception_data)
|
||||
{
|
||||
u8* tls = (u8*)getThreadLocalStorage();
|
||||
|
||||
*(u32*)(tls + 0x40) = (u32)handler;
|
||||
*(u32*)(tls + 0x44) = (u32)stack_top;
|
||||
*(u32*)(tls + 0x48) = (u32)exception_data;
|
||||
}
|
||||
|
@ -106,3 +106,30 @@ Result ERRF_ThrowResultWithMessage(Result failure, const char* message)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ERRF_ExceptionHandler(ERRF_ExceptionInfo* excep, CpuRegisters* regs)
|
||||
{
|
||||
ERRF_FatalErrInfo error;
|
||||
Result ret;
|
||||
|
||||
if (R_FAILED(ret = errfInit()))
|
||||
{
|
||||
svcBreak(USERBREAK_PANIC);
|
||||
for(;;);
|
||||
}
|
||||
|
||||
memset(&error, 0, sizeof(error));
|
||||
|
||||
error.type = ERRF_ERRTYPE_EXCEPTION;
|
||||
|
||||
error.pcAddr = regs->pc;
|
||||
getCommonErrorData(&error, 0);
|
||||
error.data.exception_data.excep = *excep;
|
||||
error.data.exception_data.regs = *regs;
|
||||
|
||||
ret = ERRF_Throw(&error);
|
||||
|
||||
errfExit();
|
||||
|
||||
for(;;);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user