Add support for user-specified exception handlers
This commit is contained in:
parent
e43d368fbc
commit
760ed8028d
@ -110,3 +110,13 @@ Result ERRF_ThrowResult(Result failure);
|
|||||||
* on development units/patched ErrDisp.
|
* on development units/patched ErrDisp.
|
||||||
*/
|
*/
|
||||||
Result ERRF_ThrowResultWithMessage(Result failure, const char* message);
|
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/result.h>
|
||||||
#include <3ds/synchronization.h>
|
#include <3ds/synchronization.h>
|
||||||
#include <3ds/svc.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
|
/// libctru thread handle type
|
||||||
typedef struct Thread_tag* Thread;
|
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.
|
* @brief Creates a new libctru thread.
|
||||||
* @param entrypoint The function that will be called first upon thread creation
|
* @param entrypoint The function that will be called first upon thread creation
|
||||||
@ -82,3 +95,26 @@ Thread threadGetCurrent(void);
|
|||||||
* @param rc Exit code
|
* @param rc Exit code
|
||||||
*/
|
*/
|
||||||
void threadExit(int rc) __attribute__((noreturn));
|
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;
|
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