marioparty4/src/Runtime.PPCEABI.H/Gecko_ExceptionPPC.cpp
2025-02-04 19:54:29 -06:00

1052 lines
27 KiB
C++
Executable file

#include "PowerPC_EABI_Support/Runtime/MWCPlusLib.h"
#include "PowerPC_EABI_Support/Runtime/Gecko_ExceptionPPC.h"
#include "PowerPC_EABI_Support/Runtime/NMWException.h"
#include "PowerPC_EABI_Support/Runtime/__ppc_eabi_linker.h"
#define RETURN_ADDRESS 4
union MWE_GeckoVector64 {
f64 d;
f32 f[2];
};
typedef union MWE_GeckoVector64 MWE_GeckoVector64;
struct GeckoFPRContext {
f64 d;
MWE_GeckoVector64 v;
};
typedef struct GeckoFPRContext GeckoFPRContext;
typedef struct ThrowContext {
GeckoFPRContext FPR[32];
s32 GPR[32];
s32 CR;
char* SP;
char* FP;
char* throwSP;
char* returnaddr;
char* throwtype;
void* location;
void* dtor;
CatchInfo* catchinfo;
} ThrowContext;
typedef ThrowContext* ThrowContextPtr;
typedef struct MWExceptionInfo {
ExceptionTableSmall* exception_record;
char* current_function;
char* action_pointer;
char* code_section;
char* data_section;
char* TOC;
} MWExceptionInfo;
typedef struct FragmentInfo {
ExceptionTableIndex* exception_start;
ExceptionTableIndex* exception_end;
char* code_start;
char* code_end;
char* data_start;
char* data_end;
char* TOC;
int active;
} FragmentInfo;
typedef struct ProcessInfo {
__eti_init_info* exception_info;
char* TOC;
int active;
} ProcessInfo;
typedef struct ActionIterator {
MWExceptionInfo info;
char* current_SP;
char* current_FP;
s32 current_R31;
} ActionIterator;
#define MAXFRAGMENTS 1
static ProcessInfo fragmentinfo[MAXFRAGMENTS];
typedef void (*DeleteFunc)(void*);
/**
* @note Address: 0x800C2374
* @note Size: 0x34
*/
int __register_fragment(struct __eti_init_info* info, char* TOC)
{
ProcessInfo* f = fragmentinfo;
int i;
for (i = 0; i < MAXFRAGMENTS; i++, f++) {
if (f->active == 0) {
f->exception_info = info;
f->TOC = TOC;
f->active = 1;
return i;
}
}
return -1;
}
/**
* @note Address: 0x800C2340
* @note Size: 0x34
*/
void __unregister_fragment(int fragmentID)
{
ProcessInfo* f;
if (fragmentID >= 0 && fragmentID < MAXFRAGMENTS) {
f = &fragmentinfo[fragmentID];
f->exception_info = 0;
f->TOC = 0;
f->active = 0;
}
}
/**
* @note Address: N/A
* @note Size: 0x88
*/
static inline int ExPPC_FindExceptionFragment(char* returnaddr, FragmentInfo* frag)
{
ProcessInfo* f;
int i;
__eti_init_info* eti_info;
for (i = 0, f = fragmentinfo; i < MAXFRAGMENTS; ++i, ++f) {
if (f->active) {
eti_info = f->exception_info;
while (1) {
if (eti_info->code_size == 0)
break;
if (returnaddr >= eti_info->code_start && returnaddr < (char*)eti_info->code_start + eti_info->code_size) {
frag->exception_start = (ExceptionTableIndex*)eti_info->eti_start;
frag->exception_end = (ExceptionTableIndex*)eti_info->eti_end;
frag->code_start = 0;
frag->code_end = 0;
frag->data_start = 0;
frag->data_end = 0;
frag->TOC = f->TOC;
frag->active = f->active;
return 1;
}
eti_info++;
}
}
}
return 0;
}
/**
* @note Address: N/A
* @note Size: 0x204
*/
static void ExPPC_FindExceptionRecord(char* returnaddr, MWExceptionInfo* info)
{
FragmentInfo* fragment;
FragmentInfo frag;
ExceptionTableIndex *exceptionindex, *p;
u32 returnoffset;
s32 i, m, n;
info->exception_record = 0;
info->action_pointer = 0;
if ((ExPPC_FindExceptionFragment(returnaddr, &frag)) == 0)
return;
fragment = &frag;
info->code_section = fragment->code_start;
info->data_section = fragment->data_start;
info->TOC = fragment->TOC;
returnoffset = returnaddr - fragment->code_start;
exceptionindex = fragment->exception_start;
for (i = 0, n = fragment->exception_end - fragment->exception_start;;) {
if (i > n)
return;
p = &exceptionindex[m = (i + n) / 2];
if (returnoffset < p->functionoffset) {
n = m - 1;
} else if (returnoffset > p->functionoffset + ETI_GetFunctionSize(p->eti_field)) {
i = m + 1;
} else
break;
}
info->current_function = fragment->code_start + p->functionoffset;
info->exception_record = ETI_GetDirectStore(p->eti_field) ? (ExceptionTableSmall*)(&p->exceptionoffset)
: (ExceptionTableSmall*)(fragment->data_start + p->exceptionoffset);
returnoffset -= p->functionoffset;
if (ET_IsLargeTable(info->exception_record->et_field)) {
ExceptionTableLarge* etl = (ExceptionTableLarge*)info->exception_record;
ExceptionRangeLarge* erl;
for (erl = etl->ranges; erl->start != 0; erl++) {
u32 range_end = erl->start + (erl->size * 4);
if (erl->start <= returnoffset && range_end >= returnoffset) {
info->action_pointer = (char*)etl + erl->action;
break;
}
}
} else {
ExceptionTableSmall* ets = (ExceptionTableSmall*)info->exception_record;
ExceptionRangeSmall* ers;
for (ers = ets->ranges; ers->start != 0; ers++) {
if (ers->start <= returnoffset && ers->end >= returnoffset) {
info->action_pointer = (char*)ets + ers->action;
break;
}
}
}
}
/**
* @note Address: N/A
* @note Size: 0x18
*/
static inline s32 ExPPC_PopR31(char* SP, MWExceptionInfo* info)
{
f64* FPR_save_area;
s32* GPR_save_area;
int saved_GPRs, saved_FPRs;
saved_FPRs = ET_GetSavedFPRs(info->exception_record->et_field);
FPR_save_area = (f64*)(SP - saved_FPRs * 8);
saved_GPRs = ET_GetSavedGPRs(info->exception_record->et_field);
GPR_save_area = (s32*)FPR_save_area;
return GPR_save_area[-1];
}
/**
* @note Address: N/A
* @note Size: 0x20
*/
static inline exaction_type ExPPC_CurrentAction(const ActionIterator* iter)
{
if (iter->info.action_pointer == 0) {
return EXACTION_ENDOFLIST;
}
return ((ex_destroylocal*)iter->info.action_pointer)->action & EXACTION_MASK;
}
/**
* @note Address: N/A
* @note Size: 0x1C0
*/
static exaction_type ExPPC_NextAction(ActionIterator* iter)
{
exaction_type action;
for (;;) {
if (iter->info.action_pointer == 0 || ((action = ((ex_destroylocal*)iter->info.action_pointer)->action) & EXACTION_ENDBIT) != 0) {
char *return_addr, *callers_SP;
callers_SP = *(char**)iter->current_SP;
if (ET_GetSavedGPRs(iter->info.exception_record->et_field)) {
iter->current_R31 = ExPPC_PopR31(callers_SP, &iter->info);
}
return_addr = *(char**)(callers_SP + RETURN_ADDRESS);
ExPPC_FindExceptionRecord(return_addr, &iter->info);
if (iter->info.exception_record == 0) {
terminate();
}
iter->current_SP = callers_SP;
iter->current_FP = (ET_GetHasFramePtr(iter->info.exception_record->et_field)) ? (char*)iter->current_R31 : iter->current_SP;
if (iter->info.action_pointer == 0)
continue;
} else {
switch (action) {
case EXACTION_DESTROYLOCAL:
iter->info.action_pointer += sizeof(ex_destroylocal);
break;
case EXACTION_DESTROYLOCALCOND:
iter->info.action_pointer += sizeof(ex_destroylocalcond);
break;
case EXACTION_DESTROYLOCALPOINTER:
iter->info.action_pointer += sizeof(ex_destroylocalpointer);
break;
case EXACTION_DESTROYLOCALARRAY:
iter->info.action_pointer += sizeof(ex_destroylocalarray);
break;
case EXACTION_DESTROYBASE:
case EXACTION_DESTROYMEMBER:
iter->info.action_pointer += sizeof(ex_destroymember);
break;
case EXACTION_DESTROYMEMBERCOND:
iter->info.action_pointer += sizeof(ex_destroymembercond);
break;
case EXACTION_DESTROYMEMBERARRAY:
iter->info.action_pointer += sizeof(ex_destroymemberarray);
break;
case EXACTION_DELETEPOINTER:
iter->info.action_pointer += sizeof(ex_deletepointer);
break;
case EXACTION_DELETEPOINTERCOND:
iter->info.action_pointer += sizeof(ex_deletepointercond);
break;
case EXACTION_CATCHBLOCK:
iter->info.action_pointer += sizeof(ex_catchblock);
break;
case EXACTION_CATCHBLOCK_32:
iter->info.action_pointer += sizeof(ex_catchblock_32);
break;
case EXACTION_ACTIVECATCHBLOCK:
iter->info.action_pointer += sizeof(ex_activecatchblock);
break;
case EXACTION_SPECIFICATION:
iter->info.action_pointer
+= sizeof(ex_specification) + ((ex_specification*)iter->info.action_pointer)->specs * sizeof(void*);
break;
default:
terminate();
}
}
action = ((ex_destroylocal*)iter->info.action_pointer)->action & EXACTION_MASK;
if (action == EXACTION_BRANCH) {
iter->info.action_pointer = ((char*)iter->info.exception_record) + ((ex_branch*)iter->info.action_pointer)->target;
action = ((ex_destroylocal*)iter->info.action_pointer)->action & EXACTION_MASK;
}
return action;
}
}
/**
* @note Address: N/A
* @note Size: 0x248
*/
static char* ExPPC_PopStackFrame(ThrowContext* context, MWExceptionInfo* info)
{
char *SP, *callers_SP;
f64* FPR_save_area;
s32* GPR_save_area;
int saved_GPRs, saved_FPRs;
GeckoFPRContext* Vector_save_area;
int i, j;
SP = context->SP;
callers_SP = *(char**)SP;
saved_FPRs = ET_GetSavedFPRs(info->exception_record->et_field);
if (ET_HasElfVector(info->exception_record->et_field)) {
Vector_save_area = (GeckoFPRContext*)(callers_SP - saved_FPRs * 16);
FPR_save_area = (f64*)Vector_save_area;
} else {
FPR_save_area = (f64*)(callers_SP - saved_FPRs * 8);
}
if (ET_HasElfVector(info->exception_record->et_field)) {
for (i = 32 - saved_FPRs, j = 0; i < 32; ++i, ++j) {
context->FPR[i].v.f[0] = Vector_save_area[j].v.f[0];
context->FPR[i].v.f[1] = Vector_save_area[j].v.f[1];
context->FPR[i].d = Vector_save_area[j].d;
}
} else {
for (i = 32 - saved_FPRs, j = 0; i < 32; ++i, ++j) {
context->FPR[i].d = FPR_save_area[j];
}
}
saved_GPRs = ET_GetSavedGPRs(info->exception_record->et_field);
GPR_save_area = (s32*)FPR_save_area;
GPR_save_area -= saved_GPRs;
for (i = 32 - saved_GPRs, j = 0; i < 32; ++i, ++j) {
context->GPR[i] = GPR_save_area[j];
}
context->SP = callers_SP;
return *(char**)(callers_SP + RETURN_ADDRESS);
}
/**
* @note Address: N/A
* @note Size: 0x3C
*/
static inline void ExPPC_DestroyLocal(ThrowContext* context, const ex_destroylocal* ex) { DTORCALL_COMPLETE(ex->dtor, context->FP + ex->local); }
/**
* @note Address: N/A
* @note Size: 0x74
*/
static inline void ExPPC_DestroyLocalCond(ThrowContext* context, const ex_destroylocalcond* ex)
{
int cond = ex_destroylocalcond_GetRegCond(ex->dlc_field) ? (local_cond_type)context->GPR[ex->cond]
: *(local_cond_type*)(context->FP + ex->cond);
if (cond) {
DTORCALL_COMPLETE(ex->dtor, context->FP + ex->local);
}
}
/**
* @note Address: N/A
* @note Size: 0x58
*/
static inline void ExPPC_DestroyLocalPointer(ThrowContext* context, const ex_destroylocalpointer* ex)
{
void* pointer
= ex_destroylocalpointer_GetRegPointer(ex->dlp_field) ? (void*)context->GPR[ex->pointer] : *(void**)(context->FP + ex->pointer);
DTORCALL_COMPLETE(ex->dtor, pointer);
}
/**
* @note Address: N/A
* @note Size: 0x84
*/
static inline void ExPPC_DestroyLocalArray(ThrowContext* context, const ex_destroylocalarray* ex)
{
char* ptr = context->FP + ex->localarray;
s32 n = ex->elements;
s32 size = ex->element_size;
for (ptr = ptr + size * n; n > 0; n--) {
ptr -= size;
DTORCALL_COMPLETE(ex->dtor, ptr);
}
}
/**
* @note Address: N/A
* @note Size: 0x64
*/
static inline void ExPPC_DestroyMember(ThrowContext* context, const ex_destroymember* ex)
{
char* objectptr
= ex_destroymember_GetRegPointer(ex->dm_field) ? (char*)context->GPR[ex->objectptr] : *(char**)(context->FP + ex->objectptr);
DTORCALL_COMPLETE(ex->dtor, objectptr + ex->offset);
}
/**
* @note Address: N/A
* @note Size: 0x64
*/
static inline void ExPPC_DestroyBase(ThrowContext* context, const ex_destroymember* ex)
{
char* objectptr
= ex_destroymember_GetRegPointer(ex->dm_field) ? (char*)context->GPR[ex->objectptr] : *(char**)(context->FP + ex->objectptr);
DTORCALL_PARTIAL(ex->dtor, objectptr + ex->offset);
}
/**
* @note Address: N/A
* @note Size: 0x98
*/
static inline void ExPPC_DestroyMemberCond(ThrowContext* context, const ex_destroymembercond* ex)
{
char* objectptr
= ex_destroymembercond_GetRegPointer(ex->dmc_field) ? (char*)context->GPR[ex->objectptr] : *(char**)(context->FP + ex->objectptr);
int cond = ex_destroymembercond_GetRegCond(ex->dmc_field) ? (vbase_ctor_arg_type)context->GPR[ex->cond]
: *(vbase_ctor_arg_type*)(context->FP + ex->cond);
if (cond) {
DTORCALL_PARTIAL(ex->dtor, objectptr + ex->offset);
}
}
/**
* @note Address: N/A
* @note Size: 0xAC
*/
static inline void ExPPC_DestroyMemberArray(ThrowContext* context, const ex_destroymemberarray* ex)
{
char* ptr
= ex_destroymemberarray_GetRegPointer(ex->dma_field) ? (char*)context->GPR[ex->objectptr] : *(char**)(context->FP + ex->objectptr);
s32 n = ex->elements;
s32 size = ex->element_size;
ptr += ex->offset;
for (ptr = ptr + size * n; n > 0; n--) {
ptr -= size;
DTORCALL_COMPLETE(ex->dtor, ptr);
}
}
/**
* @note Address: N/A
* @note Size: 0x54
*/
static inline void ExPPC_DeletePointer(ThrowContext* context, const ex_deletepointer* ex)
{
char* objectptr
= ex_deletepointer_GetRegPointer(ex->dp_field) ? (char*)context->GPR[ex->objectptr] : *(char**)(context->FP + ex->objectptr);
((DeleteFunc)ex->deletefunc)(objectptr);
}
/**
* @note Address: N/A
* @note Size: 0x8C
*/
static inline void ExPPC_DeletePointerCond(ThrowContext* context, const ex_deletepointercond* ex)
{
char* objectptr
= ex_deletepointercond_GetRegPointer(ex->dpc_field) ? (char*)context->GPR[ex->objectptr] : *(char**)(context->FP + ex->objectptr);
int cond = ex_deletepointercond_GetRegCond(ex->dpc_field) ? (local_cond_type)context->GPR[ex->cond]
: *(local_cond_type*)(context->FP + ex->cond);
if (cond) {
((DeleteFunc)ex->deletefunc)(objectptr);
}
}
/**
* @note Address: N/A
* @note Size: 0x50C
*/
static void ExPPC_UnwindStack(ThrowContext* context, MWExceptionInfo* info, void* catcher)
{
exaction_type action;
#pragma exception_terminate
for (;;) {
if (info->action_pointer == 0) {
char* return_addr;
return_addr = ExPPC_PopStackFrame(context, info);
ExPPC_FindExceptionRecord(return_addr, info);
if (info->exception_record == 0) {
terminate();
}
context->FP = (ET_GetHasFramePtr(info->exception_record->et_field)) ? (char*)context->GPR[31] : context->SP;
continue;
}
action = ((ex_destroylocal*)info->action_pointer)->action;
switch (action & EXACTION_MASK) {
case EXACTION_BRANCH:
info->action_pointer = ((char*)info->exception_record) + ((ex_branch*)info->action_pointer)->target;
break;
case EXACTION_DESTROYLOCAL:
ExPPC_DestroyLocal(context, (ex_destroylocal*)info->action_pointer);
info->action_pointer += sizeof(ex_destroylocal);
break;
case EXACTION_DESTROYLOCALCOND:
ExPPC_DestroyLocalCond(context, (ex_destroylocalcond*)info->action_pointer);
info->action_pointer += sizeof(ex_destroylocalcond);
break;
case EXACTION_DESTROYLOCALPOINTER:
ExPPC_DestroyLocalPointer(context, (ex_destroylocalpointer*)info->action_pointer);
info->action_pointer += sizeof(ex_destroylocalpointer);
break;
case EXACTION_DESTROYLOCALARRAY:
ExPPC_DestroyLocalArray(context, (ex_destroylocalarray*)info->action_pointer);
info->action_pointer += sizeof(ex_destroylocalarray);
break;
case EXACTION_DESTROYBASE:
ExPPC_DestroyBase(context, (ex_destroymember*)info->action_pointer);
info->action_pointer += sizeof(ex_destroymember);
break;
case EXACTION_DESTROYMEMBER:
ExPPC_DestroyMember(context, (ex_destroymember*)info->action_pointer);
info->action_pointer += sizeof(ex_destroymember);
break;
case EXACTION_DESTROYMEMBERCOND:
ExPPC_DestroyMemberCond(context, (ex_destroymembercond*)info->action_pointer);
info->action_pointer += sizeof(ex_destroymembercond);
break;
case EXACTION_DESTROYMEMBERARRAY:
ExPPC_DestroyMemberArray(context, (ex_destroymemberarray*)info->action_pointer);
info->action_pointer += sizeof(ex_destroymemberarray);
break;
case EXACTION_DELETEPOINTER:
ExPPC_DeletePointer(context, (ex_deletepointer*)info->action_pointer);
info->action_pointer += sizeof(ex_deletepointer);
break;
case EXACTION_DELETEPOINTERCOND:
ExPPC_DeletePointerCond(context, (ex_deletepointercond*)info->action_pointer);
info->action_pointer += sizeof(ex_deletepointercond);
break;
case EXACTION_CATCHBLOCK:
if (catcher == (void*)info->action_pointer)
return;
info->action_pointer += sizeof(ex_catchblock);
break;
case EXACTION_CATCHBLOCK_32:
if (catcher == (void*)info->action_pointer)
return;
info->action_pointer += sizeof(ex_catchblock_32);
break;
case EXACTION_ACTIVECATCHBLOCK: {
CatchInfo* catchinfo;
catchinfo = (CatchInfo*)(context->FP + ((ex_activecatchblock*)info->action_pointer)->cinfo_ref);
if (catchinfo->dtor) {
if (context->location == catchinfo->location) {
context->dtor = catchinfo->dtor;
} else {
DTORCALL_COMPLETE(catchinfo->dtor, catchinfo->location);
}
}
info->action_pointer += sizeof(ex_activecatchblock);
} break;
case EXACTION_SPECIFICATION:
if (catcher == (void*)info->action_pointer)
return;
info->action_pointer += sizeof(ex_specification) + ((ex_specification*)info->action_pointer)->specs * sizeof(void*);
break;
default:
terminate();
}
if (action & EXACTION_ENDBIT)
info->action_pointer = 0;
}
}
/**
* @note Address: N/A
* @note Size: 0x88
*/
static inline int ExPPC_IsInSpecification(char* extype, ex_specification* spec)
{
s32 i, offset;
for (i = 0; i < spec->specs; i++) {
if (__throw_catch_compare(extype, spec->spec[i], &offset))
return 1;
}
return 0;
}
/**
* @note Address: N/A
* @note Size: 0x1B4
*/
extern void __unexpected(CatchInfo* catchinfo)
{
ex_specification* unexp = (ex_specification*)catchinfo->stacktop;
#pragma exception_magic // allow access to __exception_magic in try/catch blocks
try {
unexpected();
} catch (...) {
if (ExPPC_IsInSpecification((char*)((CatchInfo*)&__exception_magic)->typeinfo, unexp)) {
throw;
}
if (ExPPC_IsInSpecification("!bad_exception!!", unexp)) {
throw bad_exception();
}
if (ExPPC_IsInSpecification("!std::bad_exception!!", unexp)) {
throw bad_exception();
}
}
terminate();
}
/**
* @note Address: N/A
* @note Size: 0x104
*/
asm static void ExPPC_LongJump(register ThrowContext* context, register void* newRTOC, register void* newPC)
{
#ifdef __MWERKS__ // clang-format off
nofralloc
mr r8, newPC
mr RTOC, newRTOC
lwz r0, context->CR
mtcrf 255, r0
lmw r13, context->GPR[13]
la r7, context->FPR[14].v
psq_lx fp14, 0, r7, 0, 0
lfd fp14, context->FPR[14].d
la r7, context->FPR[15].v
psq_lx fp15, 0, r7, 0, 0
lfd fp15, context->FPR[15].d
la r7, context->FPR[16].v
psq_lx fp16, 0, r7, 0, 0
lfd fp16, context->FPR[16].d
la r7, context->FPR[17].v
psq_lx fp17, 0, r7, 0, 0
lfd fp17, context->FPR[17].d
la r7, context->FPR[18].v
psq_lx fp18, 0, r7, 0, 0
lfd fp18, context->FPR[18].d
la r7, context->FPR[19].v
psq_lx fp19, 0, r7, 0, 0
lfd fp19, context->FPR[19].d
la r7, context->FPR[20].v
psq_lx fp20, 0, r7, 0, 0
lfd fp20, context->FPR[20].d
la r7, context->FPR[21].v
psq_lx fp21, 0, r7, 0, 0
lfd fp21, context->FPR[21].d
la r7, context->FPR[22].v
psq_lx fp22, 0, r7, 0, 0
lfd fp22, context->FPR[22].d
la r7, context->FPR[23].v
psq_lx fp23, 0, r7, 0, 0
lfd fp23, context->FPR[23].d
la r7, context->FPR[24].v
psq_lx fp24, 0, r7, 0, 0
lfd fp24, context->FPR[24].d
la r7, context->FPR[25].v
psq_lx fp25, 0, r7, 0, 0
lfd fp25, context->FPR[25].d
la r7, context->FPR[26].v
psq_lx fp26, 0, r7, 0, 0
lfd fp26, context->FPR[26].d
la r7, context->FPR[27].v
psq_lx fp27, 0, r7, 0, 0
lfd fp27, context->FPR[27].d
la r7, context->FPR[28].v
psq_lx fp28, 0, r7, 0, 0
lfd fp28, context->FPR[28].d
la r7, context->FPR[29].v
psq_lx fp29, 0, r7, 0, 0
lfd fp29, context->FPR[29].d
la r7, context->FPR[30].v
psq_lx fp30, 0, r7, 0, 0
lfd fp30, context->FPR[30].d
la r7, context->FPR[31].v
psq_lx fp31, 0, r7, 0, 0
lfd fp31, context->FPR[31].d
mtlr r8
lwz SP, context->throwSP
lwz r3, context->SP
lwz r3, 0(r3)
stw r3, 0(SP)
blr
#endif // clang-format on
}
/**
* @note Address: N/A
* @note Size: 0x84
*/
static inline void ExPPC_HandleUnexpected(ThrowContext* context, MWExceptionInfo* info, ex_specification* unexp)
{
CatchInfo* catchinfo;
#pragma exception_terminate
ExPPC_UnwindStack(context, info, unexp);
catchinfo = (CatchInfo*)(context->FP + unexp->cinfo_ref);
catchinfo->location = context->location;
catchinfo->typeinfo = context->throwtype;
catchinfo->dtor = context->dtor;
catchinfo->stacktop = unexp;
ExPPC_LongJump(context, info->TOC, info->current_function + unexp->pcoffset);
}
/**
* @note Address: N/A
* @note Size: 0x410
*/
static void ExPPC_ThrowHandler(ThrowContext* context)
{
ActionIterator iter;
MWExceptionInfo info;
exaction_type action;
CatchInfo* catchinfo;
s32 offset;
ExPPC_FindExceptionRecord(context->returnaddr, &info);
if (info.exception_record == 0) {
terminate();
}
context->FP = (ET_GetHasFramePtr(info.exception_record->et_field)) ? (char*)context->GPR[31] : context->SP;
if (context->throwtype == 0) {
iter.info = info;
iter.current_SP = context->SP;
iter.current_FP = context->FP;
iter.current_R31 = context->GPR[31];
for (action = ExPPC_CurrentAction(&iter);; action = ExPPC_NextAction(&iter)) {
switch (action) {
case EXACTION_ACTIVECATCHBLOCK:
break;
case EXACTION_ENDOFLIST:
case EXACTION_DESTROYLOCAL:
case EXACTION_DESTROYLOCALCOND:
case EXACTION_DESTROYLOCALPOINTER:
case EXACTION_DESTROYLOCALARRAY:
case EXACTION_DESTROYBASE:
case EXACTION_DESTROYMEMBER:
case EXACTION_DESTROYMEMBERCOND:
case EXACTION_DESTROYMEMBERARRAY:
case EXACTION_DELETEPOINTER:
case EXACTION_DELETEPOINTERCOND:
case EXACTION_CATCHBLOCK:
case EXACTION_CATCHBLOCK_32:
case EXACTION_SPECIFICATION:
continue;
case EXACTION_TERMINATE:
default:
terminate();
}
break;
}
catchinfo = (CatchInfo*)(iter.current_FP + ((ex_activecatchblock*)iter.info.action_pointer)->cinfo_ref);
context->throwtype = (char*)catchinfo->typeinfo;
context->location = catchinfo->location;
context->dtor = 0;
context->catchinfo = catchinfo;
} else {
context->catchinfo = 0L;
}
iter.info = info;
iter.current_SP = context->SP;
iter.current_FP = context->FP;
iter.current_R31 = context->GPR[31];
for (action = ExPPC_CurrentAction(&iter);; action = ExPPC_NextAction(&iter)) {
switch (action) {
case EXACTION_CATCHBLOCK_32:
if (__throw_catch_compare(context->throwtype, ((ex_catchblock_32*)iter.info.action_pointer)->catch_type, &offset)) {
break;
}
continue;
case EXACTION_CATCHBLOCK:
if (__throw_catch_compare(context->throwtype, ((ex_catchblock*)iter.info.action_pointer)->catch_type, &offset)) {
break;
}
continue;
case EXACTION_SPECIFICATION:
if (!ExPPC_IsInSpecification(context->throwtype, (ex_specification*)iter.info.action_pointer)) {
ExPPC_HandleUnexpected(context, &info, (ex_specification*)iter.info.action_pointer);
}
continue;
case EXACTION_ENDOFLIST:
case EXACTION_DESTROYLOCAL:
case EXACTION_DESTROYLOCALCOND:
case EXACTION_DESTROYLOCALPOINTER:
case EXACTION_DESTROYLOCALARRAY:
case EXACTION_DESTROYBASE:
case EXACTION_DESTROYMEMBER:
case EXACTION_DESTROYMEMBERCOND:
case EXACTION_DESTROYMEMBERARRAY:
case EXACTION_DELETEPOINTER:
case EXACTION_DELETEPOINTERCOND:
case EXACTION_ACTIVECATCHBLOCK:
continue;
case EXACTION_TERMINATE:
default:
terminate();
}
break;
}
if (action == EXACTION_CATCHBLOCK_32) {
ex_catchblock_32* catchblock_32;
catchblock_32 = (ex_catchblock_32*)iter.info.action_pointer;
ExPPC_UnwindStack(context, &info, catchblock_32);
catchinfo = (CatchInfo*)(context->FP + catchblock_32->cinfo_ref);
catchinfo->location = context->location;
catchinfo->typeinfo = context->throwtype;
catchinfo->dtor = context->dtor;
if (*context->throwtype == '*') {
catchinfo->sublocation = &catchinfo->pointercopy;
catchinfo->pointercopy = *(s32*)context->location + offset;
} else {
catchinfo->sublocation = (char*)context->location + offset;
}
ExPPC_LongJump(context, info.TOC, info.current_function + catchblock_32->catch_pcoffset);
} else {
ex_catchblock* catchblock;
catchblock = (ex_catchblock*)iter.info.action_pointer;
ExPPC_UnwindStack(context, &info, catchblock);
catchinfo = (CatchInfo*)(context->FP + catchblock->cinfo_ref);
catchinfo->location = context->location;
catchinfo->typeinfo = context->throwtype;
catchinfo->dtor = context->dtor;
if (*context->throwtype == '*') {
catchinfo->sublocation = &catchinfo->pointercopy;
catchinfo->pointercopy = *(s32*)context->location + offset;
} else {
catchinfo->sublocation = (char*)context->location + offset;
}
ExPPC_LongJump(context, info.TOC, info.current_function + catchblock->catch_pcoffset);
}
}
/**
* @note Address: N/A
* @note Size: 0x44
*/
void __end__catch(CatchInfo* catchinfo)
{
if (catchinfo->location && catchinfo->dtor) {
DTORCALL_COMPLETE(catchinfo->dtor, catchinfo->location);
}
}
/**
* @note Address: N/A
* @note Size: 0x144
*/
asm void __throw(char* throwtype, void* location, void* dtor)
{
#ifdef __MWERKS__ // clang-format off
ThrowContext throwcontext;
fralloc
stmw r13, throwcontext.GPR[13]
stfd fp14, throwcontext.FPR[14].d
la r3, throwcontext.FPR[14].v
psq_stx fp14, 0, r3,0,0
stfd fp15, throwcontext.FPR[15].d
la r3, throwcontext.FPR[15].v
psq_stx fp15, 0, r3, 0, 0
stfd fp16, throwcontext.FPR[16].d
la r3, throwcontext.FPR[16].v
psq_stx fp16, 0, r3, 0, 0
stfd fp17, throwcontext.FPR[17].d
la r3, throwcontext.FPR[17].v
psq_stx fp17, 0, r3, 0, 0
stfd fp18, throwcontext.FPR[18].d
la r3, throwcontext.FPR[18].v
psq_stx fp18, 0, r3, 0, 0
stfd fp19, throwcontext.FPR[19].d
la r3, throwcontext.FPR[19].v
psq_stx fp19, 0, r3, 0, 0
stfd fp20, throwcontext.FPR[20].d
la r3, throwcontext.FPR[20].v
psq_stx fp20, 0, r3, 0, 0
stfd fp21, throwcontext.FPR[21].d
la r3, throwcontext.FPR[21].v
psq_stx fp21, 0, r3, 0, 0
stfd fp22, throwcontext.FPR[22].d
la r3, throwcontext.FPR[22].v
psq_stx fp22, 0, r3, 0, 0
stfd fp23, throwcontext.FPR[23].d
la r3, throwcontext.FPR[23].v
psq_stx fp23, 0, r3, 0, 0
stfd fp24, throwcontext.FPR[24].d
la r3, throwcontext.FPR[24].v
psq_stx fp24, 0, r3, 0, 0
stfd fp25, throwcontext.FPR[25].d
la r3, throwcontext.FPR[25].v
psq_stx fp25, 0, r3, 0, 0
stfd fp26, throwcontext.FPR[26].d
la r3, throwcontext.FPR[26].v
psq_stx fp26, 0, r3, 0, 0
stfd fp27, throwcontext.FPR[27].d
la r3, throwcontext.FPR[27].v
psq_stx fp27, 0, r3, 0, 0
stfd fp28, throwcontext.FPR[28].d
la r3, throwcontext.FPR[28].v
psq_stx fp28, 0, r3, 0, 0
stfd fp29, throwcontext.FPR[29].d
la r3, throwcontext.FPR[29].v
psq_stx fp29, 0, r3, 0, 0
stfd fp30, throwcontext.FPR[30].d
la r3, throwcontext.FPR[30].v
psq_stx fp30, 0, r3, 0, 0
stfd fp31, throwcontext.FPR[31].d
la r3, throwcontext.FPR[31].v
psq_stx fp31, 0, r3, 0, 0
mfcr r3
stw r3, throwcontext.CR;
lwz r3, 0(sp)
lwz r4, RETURN_ADDRESS(r3)
stw r3, throwcontext.SP;
stw r3, throwcontext.throwSP;
stw r4, throwcontext.returnaddr;
lwz r3,throwtype
stw r3, throwcontext.throwtype
lwz r3,location
stw r3, throwcontext.location
lwz r3,dtor
stw r3, throwcontext.dtor
la r3, throwcontext
bl ExPPC_ThrowHandler
nop
frfree
blr
#endif // clang-format on
}