From d340ccf0618f81b0d83a91c7a514f0194fc0a580 Mon Sep 17 00:00:00 2001 From: mrshigure Date: Tue, 4 Feb 2025 17:54:29 -0800 Subject: [PATCH] Making some Runtime progress (#557) --- config/GMPE01_00/rels/m463Dll/symbols.txt | 2 +- config/GMPE01_00/splits.txt | 4 +- config/GMPE01_00/symbols.txt | 8 +- config/GMPE01_01/splits.txt | 4 +- configure.py | 12 +- .../Runtime/Gecko_ExceptionPPC.h | 231 ++++ .../Runtime/NMWException.h | 22 +- .../PowerPC_EABI_Support/Runtime/exception.h | 38 + src/MSL_C.PPCEABI.bare.H/abort_exit.c | 1 - src/Runtime.PPCEABI.H/GCN_mem_alloc.c | 30 + src/Runtime.PPCEABI.H/Gecko_ExceptionPPC.cpp | 1052 +++++++++++++++++ src/Runtime.PPCEABI.H/NMWException.cpp | 157 +++ 12 files changed, 1537 insertions(+), 24 deletions(-) create mode 100755 include/PowerPC_EABI_Support/Runtime/Gecko_ExceptionPPC.h create mode 100755 include/PowerPC_EABI_Support/Runtime/exception.h create mode 100755 src/Runtime.PPCEABI.H/GCN_mem_alloc.c create mode 100755 src/Runtime.PPCEABI.H/Gecko_ExceptionPPC.cpp create mode 100755 src/Runtime.PPCEABI.H/NMWException.cpp diff --git a/config/GMPE01_00/rels/m463Dll/symbols.txt b/config/GMPE01_00/rels/m463Dll/symbols.txt index 351f689b..e336c47f 100644 --- a/config/GMPE01_00/rels/m463Dll/symbols.txt +++ b/config/GMPE01_00/rels/m463Dll/symbols.txt @@ -157,7 +157,7 @@ lbl_1_bss_54 = .bss:0x00000054; // type:object size:0x4 data:4byte lbl_1_bss_58 = .bss:0x00000058; // type:object size:0x4 data:4byte lbl_1_bss_5C = .bss:0x0000005C; // type:object size:0x2D0 lbl_1_bss_32C = .bss:0x0000032C; // type:object size:0x4 data:4byte -lbl_1_bss_330 = .bss:0x00000330; // type:object size:0x24 data:4byte +lbl_1_bss_330 = .bss:0x00000330; // type:object size:0x24 scope:local data:4byte lbl_1_bss_354 = .bss:0x00000354; // type:object size:0x4 data:4byte lbl_1_bss_358 = .bss:0x00000358; // type:object size:0x4 data:4byte lbl_1_bss_35C = .bss:0x0000035C; // type:object size:0x1C0 data:4byte diff --git a/config/GMPE01_00/splits.txt b/config/GMPE01_00/splits.txt index d7d8237a..4751f858 100644 --- a/config/GMPE01_00/splits.txt +++ b/config/GMPE01_00/splits.txt @@ -955,7 +955,7 @@ Runtime.PPCEABI.H/NewMore.cp: .data start:0x8013E208 end:0x8013E218 .sdata start:0x801D39A0 end:0x801D39A8 -Runtime.PPCEABI.H/NMWException.cp: +Runtime.PPCEABI.H/NMWException.cpp: extab start:0x80005650 end:0x80005670 extabindex start:0x80005718 end:0x80005748 .text start:0x800E2108 end:0x800E23CC @@ -971,7 +971,7 @@ Runtime.PPCEABI.H/__init_cpp_exceptions.cpp: .dtors start:0x8011DCE0 end:0x8011DCE8 .sdata start:0x801D39B0 end:0x801D39B8 -Runtime.PPCEABI.H/Gecko_ExceptionPPC.cp: +Runtime.PPCEABI.H/Gecko_ExceptionPPC.cpp: extab start:0x80005670 end:0x800056E4 extabindex start:0x80005748 end:0x8000579C .text start:0x800E2B24 end:0x800E3F5C diff --git a/config/GMPE01_00/symbols.txt b/config/GMPE01_00/symbols.txt index d4d7595a..43ae5aae 100644 --- a/config/GMPE01_00/symbols.txt +++ b/config/GMPE01_00/symbols.txt @@ -3646,10 +3646,10 @@ __THPAANScaleFactor = .rodata:0x8011E490; // type:object size:0x40 data:byte lbl_8011E4D0 = .rodata:0x8011E4D0; // type:object size:0x10 lbl_8011E4E0 = .rodata:0x8011E4E0; // type:object size:0x10 __constants = .rodata:0x8011E4F0; // type:object size:0x18 scope:local data:double -lbl_8011E508 = .rodata:0x8011E508; // type:object size:0x54 -lbl_8011E55C = .rodata:0x8011E55C; // type:object size:0x14 -lbl_8011E570 = .rodata:0x8011E570; // type:object size:0x10 -lbl_8011E580 = .rodata:0x8011E580; // type:object size:0x20 +lbl_8011E508 = .rodata:0x8011E508; // type:object size:0x54 data:string +lbl_8011E55C = .rodata:0x8011E55C; // type:object size:0x14 data:string +lbl_8011E570 = .rodata:0x8011E570; // type:object size:0x10 data:string +lbl_8011E580 = .rodata:0x8011E580; // type:object size:0x20 data:string lbl_8011E5A0 = .rodata:0x8011E5A0; // type:object size:0x38 lbl_8011E5D8 = .rodata:0x8011E5D8; // type:object size:0x40 fix_pool_sizes = .rodata:0x8011E618; // type:object size:0x18 scope:local data:4byte diff --git a/config/GMPE01_01/splits.txt b/config/GMPE01_01/splits.txt index d7d8237a..4751f858 100644 --- a/config/GMPE01_01/splits.txt +++ b/config/GMPE01_01/splits.txt @@ -955,7 +955,7 @@ Runtime.PPCEABI.H/NewMore.cp: .data start:0x8013E208 end:0x8013E218 .sdata start:0x801D39A0 end:0x801D39A8 -Runtime.PPCEABI.H/NMWException.cp: +Runtime.PPCEABI.H/NMWException.cpp: extab start:0x80005650 end:0x80005670 extabindex start:0x80005718 end:0x80005748 .text start:0x800E2108 end:0x800E23CC @@ -971,7 +971,7 @@ Runtime.PPCEABI.H/__init_cpp_exceptions.cpp: .dtors start:0x8011DCE0 end:0x8011DCE8 .sdata start:0x801D39B0 end:0x801D39B8 -Runtime.PPCEABI.H/Gecko_ExceptionPPC.cp: +Runtime.PPCEABI.H/Gecko_ExceptionPPC.cpp: extab start:0x80005670 end:0x800056E4 extabindex start:0x80005748 end:0x8000579C .text start:0x800E2B24 end:0x800E3F5C diff --git a/configure.py b/configure.py index b3b128bd..6d5e0024 100644 --- a/configure.py +++ b/configure.py @@ -209,7 +209,7 @@ else: cflags_runtime = [ *cflags_base, "-use_lmw_stmw on", - "-str reuse,pool,readonly", + "-str reuse,readonly", "-common off", "-inline auto,deferred", ] @@ -668,11 +668,15 @@ config.libs = [ Object(MatchingFor("GMPE01_00", "GMPE01_01"), "Runtime.PPCEABI.H/__mem.c"), Object(NonMatching, "Runtime.PPCEABI.H/New.cp"), Object(NonMatching, "Runtime.PPCEABI.H/NewMore.cp"), - Object(NonMatching, "Runtime.PPCEABI.H/NMWException.cp"), + Object(NonMatching, "Runtime.PPCEABI.H/NMWException.cpp"), Object(MatchingFor("GMPE01_00", "GMPE01_01"), "Runtime.PPCEABI.H/runtime.c"), Object(MatchingFor("GMPE01_00", "GMPE01_01"), "Runtime.PPCEABI.H/__init_cpp_exceptions.cpp"), - Object(NonMatching, "Runtime.PPCEABI.H/Gecko_ExceptionPPC.cp"), - Object(NonMatching, "Runtime.PPCEABI.H/GCN_mem_alloc.c"), + Object( + NonMatching, + "Runtime.PPCEABI.H/Gecko_ExceptionPPC.cpp", + extra_cflags=["-Cpp_exceptions on"] + ), + Object(MatchingFor("GMPE01_00", "GMPE01_01"), "Runtime.PPCEABI.H/GCN_mem_alloc.c"), ], }, { diff --git a/include/PowerPC_EABI_Support/Runtime/Gecko_ExceptionPPC.h b/include/PowerPC_EABI_Support/Runtime/Gecko_ExceptionPPC.h new file mode 100755 index 00000000..a864ea0d --- /dev/null +++ b/include/PowerPC_EABI_Support/Runtime/Gecko_ExceptionPPC.h @@ -0,0 +1,231 @@ +#ifndef _RUNTIME_GECKO_EXCEPTIONPPC_H +#define _RUNTIME_GECKO_EXCEPTIONPPC_H + +#include + +typedef u8 exaction_type; + +#define EXACTION_ENDBIT 0x80 +#define EXACTION_MASK 0x7F + +// EXAction structs + +#define EXACTION_ENDOFLIST 0 +#define EXACTION_BRANCH 1 + +typedef struct ex_branch { + exaction_type action; + u8 unused; + u16 target; +} ex_branch; + +#define EXACTION_DESTROYLOCAL 2 + +typedef struct ex_destroylocal { + exaction_type action; + u8 unused; + s16 local; + void* dtor; +} ex_destroylocal; + +#define EXACTION_DESTROYLOCALCOND 3 + +typedef struct ex_destroylocalcond { + exaction_type action; + u8 dlc_field; + s16 cond; + s16 local; + void* dtor; +} ex_destroylocalcond; + +#define ex_destroylocalcond_MakeField(regcond) (((regcond) << 7)) +#define ex_destroylocalcond_GetRegCond(field) ((field) >> 7) + +#define EXACTION_DESTROYLOCALPOINTER 4 + +typedef struct ex_destroylocalpointer { + exaction_type action; + u8 dlp_field; + s16 pointer; + void* dtor; +} ex_destroylocalpointer; + +#define ex_destroylocalpointer_MakeField(regpointer) (((regpointer) << 7)) +#define ex_destroylocalpointer_GetRegPointer(field) ((field) >> 7) + +#define EXACTION_DESTROYLOCALARRAY 5 + +typedef struct ex_destroylocalarray { + exaction_type action; + u8 unused; + s16 localarray; + u16 elements; + u16 element_size; + void* dtor; +} ex_destroylocalarray; + +#define EXACTION_DESTROYBASE 6 +#define EXACTION_DESTROYMEMBER 7 + +typedef struct ex_destroymember { + exaction_type action; + u8 dm_field; + s16 objectptr; + s32 offset; + void* dtor; +} ex_destroymember; + +#define ex_destroymember_MakeField(regpointer) (((regpointer) << 7)) +#define ex_destroymember_GetRegPointer(field) ((field) >> 7) + +#define EXACTION_DESTROYMEMBERCOND 8 + +typedef struct ex_destroymembercond { + exaction_type action; + u8 dmc_field; + s16 cond; + s16 objectptr; + s32 offset; + void* dtor; +} ex_destroymembercond; + +#define ex_destroymembercond_MakeField(regcond, regpointer) (((regcond) << 7) | (((regpointer)&0x1) << 6)) +#define ex_destroymembercond_GetRegCond(field) ((field) >> 7) +#define ex_destroymembercond_GetRegPointer(field) (((field) >> 6) & 0x1) + +#define EXACTION_DESTROYMEMBERARRAY 9 + +typedef struct ex_destroymemberarray { + exaction_type action; + u8 dma_field; + s16 objectptr; + s32 offset; + s32 elements; + s32 element_size; + void* dtor; +} ex_destroymemberarray; + +#define ex_destroymemberarray_MakeField(regpointer) (((regpointer) << 7)) +#define ex_destroymemberarray_GetRegPointer(field) ((field) >> 7) + +#define EXACTION_DELETEPOINTER 10 + +typedef struct ex_deletepointer { + exaction_type action; + u8 dp_field; + s16 objectptr; + void* deletefunc; +} ex_deletepointer; + +#define ex_deletepointer_MakeField(regpointer) (((regpointer) << 7)) +#define ex_deletepointer_GetRegPointer(field) ((field) >> 7) + +#define EXACTION_DELETEPOINTERCOND 11 + +typedef struct ex_deletepointercond { + exaction_type action; + u8 dpc_field; + s16 cond; + s16 objectptr; + void* deletefunc; +} ex_deletepointercond; + +#define ex_deletepointercond_MakeField(regcond, regpointer) (((regcond) << 7) | (((regpointer)&0x1) << 6)) +#define ex_deletepointercond_GetRegCond(field) ((field) >> 7) +#define ex_deletepointercond_GetRegPointer(field) (((field) >> 6) & 0x1) + +#define EXACTION_CATCHBLOCK 12 + +typedef struct ex_catchblock { + exaction_type action; + u8 unused; + char* catch_type; + u16 catch_pcoffset; + s16 cinfo_ref; +} ex_catchblock; + +#define EXACTION_ACTIVECATCHBLOCK 13 + +typedef struct ex_activecatchblock { + exaction_type action; + u8 unused; + s16 cinfo_ref; +} ex_activecatchblock; + +#define EXACTION_TERMINATE 14 + +typedef struct ex_terminate { + exaction_type action; + u8 unused; +} ex_terminate; + +#define EXACTION_SPECIFICATION 15 + +typedef struct ex_specification { + exaction_type action; + u8 unused; + u16 specs; + s32 pcoffset; + s32 cinfo_ref; + char* spec[]; +} ex_specification; + +#define EXACTION_CATCHBLOCK_32 16 + +typedef struct ex_catchblock_32 { + exaction_type action; + u8 unused; + char* catch_type; + s32 catch_pcoffset; + s32 cinfo_ref; +} ex_catchblock_32; + +// Other structs + +typedef struct ExceptionRangeSmall { + u16 start; + u16 end; + u16 action; +} ExceptionRangeSmall; + +typedef struct ExceptionTableSmall { + u16 et_field; + ExceptionRangeSmall ranges[0]; +} ExceptionTableSmall; + +typedef struct ExceptionRangeLarge { + u32 start; + u16 size; + u16 action; +} ExceptionRangeLarge; + +typedef struct ExceptionTableLarge { + u16 et_field; + u16 et_field2; + ExceptionRangeLarge ranges[]; +} ExceptionTableLarge; + +#define ET_MakeField(savedGPRs, savedFPRs, savedCR, hasframeptr, isLarge) \ + (((savedGPRs) << 11) | ((savedFPRs & 0x1f) << 6) | ((savedCR & 0x1) << 5) | ((hasframeptr & 0x1) << 4) | ((isLarge & 1) << 3)) + +#define ET_GetSavedGPRs(field) ((field) >> 11) +#define ET_GetSavedFPRs(field) (((field) >> 6) & 0x1f) +#define ET_GetSavedCR(field) (((field) >> 5) & 0x1) +#define ET_GetHasFramePtr(field) (((field) >> 4) & 0x1) +#define ET_IsLargeTable(field) (((field) >> 3) & 0x1) +#define ET_ClearLargeBit(field) ((field) & ~(1 << 3)) +#define ET_SetLargeBit(field) ((field) | (1 << 3)) + +#define ET_HasElfVector(field) (((field) >> 1) & 0x1) + +typedef struct ExceptionTableIndex { + u32 functionoffset; + u32 eti_field; + u32 exceptionoffset; +} ExceptionTableIndex; + +#define ETI_MakeField(direct, fsize) ((((s32)(direct)) << 31) | ((fsize)&0x7fffffff)) +#define ETI_GetDirectStore(field) ((field) >> 31) +#define ETI_GetFunctionSize(field) ((field)&0x7fffffff) + +#endif diff --git a/include/PowerPC_EABI_Support/Runtime/NMWException.h b/include/PowerPC_EABI_Support/Runtime/NMWException.h index 2358f785..aba83f4d 100644 --- a/include/PowerPC_EABI_Support/Runtime/NMWException.h +++ b/include/PowerPC_EABI_Support/Runtime/NMWException.h @@ -1,7 +1,15 @@ #ifndef _NMWEXCEPTION #define _NMWEXCEPTION -typedef short vbase_ctor_arg_type; +#include "types.h" +#include "PowerPC_EABI_Support/Runtime/exception.h" +#include "PowerPC_EABI_Support/Runtime/__ppc_eabi_linker.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef s16 vbase_ctor_arg_type; typedef char local_cond_type; typedef struct CatchInfo { @@ -9,7 +17,7 @@ typedef struct CatchInfo { void* typeinfo; void* dtor; void* sublocation; - long pointercopy; + s32 pointercopy; void* stacktop; } CatchInfo; @@ -19,18 +27,12 @@ typedef struct DestructorChain { void* object; } DestructorChain; -#ifdef __cplusplus -extern "C" { -#endif - -extern void* __register_global_object(void* object, void* destructor, - void* registration); +extern void* __register_global_object(void* object, void* destructor, void* registration); extern void __destroy_global_chain(void); extern void __end__catch(CatchInfo* catchinfo); extern void __throw(char* throwtype, void* location, void* dtor); -extern char __throw_catch_compare(const char* throwtype, const char* catchtype, - long* offset_result); +extern char __throw_catch_compare(const char* throwtype, const char* catchtype, s32* offset_result); extern void __unexpected(CatchInfo* catchinfo); extern int __register_fragment(struct __eti_init_info* info, char* TOC); diff --git a/include/PowerPC_EABI_Support/Runtime/exception.h b/include/PowerPC_EABI_Support/Runtime/exception.h new file mode 100755 index 00000000..2530b3de --- /dev/null +++ b/include/PowerPC_EABI_Support/Runtime/exception.h @@ -0,0 +1,38 @@ +#ifndef _EXCEPTION +#define _EXCEPTION + +namespace std { +class exception { +public: + exception() { } + virtual ~exception() { } + virtual const char* what() const { return "exception"; } +}; + +class bad_exception : public exception { +public: + bad_exception() { } + virtual ~bad_exception() { } + virtual const char* what() const { return "bad_exception"; } +}; + +typedef void (*unexpected_handler)(); +unexpected_handler set_unexpected(unexpected_handler handler); +void unexpected(); + +typedef void (*terminate_handler)(); +terminate_handler set_terminate(terminate_handler handler); +void terminate(); + +} // namespace std + +using std::bad_exception; +using std::exception; +using std::set_terminate; +using std::set_unexpected; +using std::terminate; +using std::terminate_handler; +using std::unexpected; +using std::unexpected_handler; + +#endif diff --git a/src/MSL_C.PPCEABI.bare.H/abort_exit.c b/src/MSL_C.PPCEABI.bare.H/abort_exit.c index b54f4742..4432d145 100644 --- a/src/MSL_C.PPCEABI.bare.H/abort_exit.c +++ b/src/MSL_C.PPCEABI.bare.H/abort_exit.c @@ -2,7 +2,6 @@ #include "PowerPC_EABI_Support/Msl/MSL_C/MSL_Common/critical_regions.h" #include "PowerPC_EABI_Support/Msl/MSL_C/MSL_Common/signal.h" #include "stddef.h" -#include "PowerPC_EABI_Support/Runtime/NMWException.h" void _ExitProcess(); diff --git a/src/Runtime.PPCEABI.H/GCN_mem_alloc.c b/src/Runtime.PPCEABI.H/GCN_mem_alloc.c new file mode 100755 index 00000000..c36465e2 --- /dev/null +++ b/src/Runtime.PPCEABI.H/GCN_mem_alloc.c @@ -0,0 +1,30 @@ +#include "dolphin/os.h" + +inline static void InitDefaultHeap(void) { + void* arenaLo; + void* arenaHi; + + OSReport("GCN_Mem_Alloc.c : InitDefaultHeap. No Heap Available\n"); + OSReport("Metrowerks CW runtime library initializing default heap\n"); + + arenaLo = OSGetArenaLo(); + arenaHi = OSGetArenaHi(); + + arenaLo = OSInitAlloc(arenaLo, arenaHi, 1); + OSSetArenaLo(arenaLo); + + arenaLo = OSRoundUpPtr(arenaLo, 0x20); + arenaHi = OSRoundDownPtr(arenaHi, 0x20); + + OSSetCurrentHeap(OSCreateHeap(arenaLo, arenaHi)); + OSSetArenaLo(arenaLo = arenaHi); +} + +/* 80362914-803629CC 35D254 00B8+00 0/0 1/1 0/0 .text __sys_free */ +void __sys_free(void* p) { + if (__OSCurrHeap == -1) { + InitDefaultHeap(); + } + + OSFreeToHeap(__OSCurrHeap, p); +} diff --git a/src/Runtime.PPCEABI.H/Gecko_ExceptionPPC.cpp b/src/Runtime.PPCEABI.H/Gecko_ExceptionPPC.cpp new file mode 100755 index 00000000..faa1385f --- /dev/null +++ b/src/Runtime.PPCEABI.H/Gecko_ExceptionPPC.cpp @@ -0,0 +1,1052 @@ +#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 +} diff --git a/src/Runtime.PPCEABI.H/NMWException.cpp b/src/Runtime.PPCEABI.H/NMWException.cpp new file mode 100755 index 00000000..b5f722de --- /dev/null +++ b/src/Runtime.PPCEABI.H/NMWException.cpp @@ -0,0 +1,157 @@ +#include "PowerPC_EABI_Support/Runtime/NMWException.h" +#include "PowerPC_EABI_Support/Runtime/MWCPlusLib.h" + +#define ARRAY_HEADER_SIZE 16 + +extern "C" { +extern void abort(); +} + +namespace std { +/** + * @note Address: N/A + * @note Size: 0x20 + */ +static void dthandler() { abort(); } + +static terminate_handler thandler = dthandler; + +/** + * @note Address: N/A + * @note Size: 0x28 + */ +static void duhandler() { terminate(); } + +static unexpected_handler uhandler = duhandler; + +/** + * @note Address: N/A + * @note Size: 0x28 + */ +extern void terminate() { thandler(); } + +/** + * @note Address: N/A + * @note Size: 0x28 + */ +extern void unexpected() { uhandler(); } +} // namespace std + +/** + * @note Address: N/A + * @note Size: 0x22C + */ +extern char __throw_catch_compare(const char* throwtype, const char* catchtype, s32* offset_result) +{ + const char *cptr1, *cptr2; + + *offset_result = 0; + + if ((cptr2 = catchtype) == 0) { + return true; + } + + cptr1 = throwtype; + + if (*cptr2 == 'P') { + cptr2++; + if (*cptr2 == 'C') + cptr2++; + if (*cptr2 == 'V') + cptr2++; + if (*cptr2 == 'v') { + if (*cptr1 == 'P' || *cptr1 == '*') { + return true; + } + } + cptr2 = catchtype; + } + + switch (*cptr1) { + case '*': + case '!': + if (*cptr1++ != *cptr2++) + return false; + for (;;) { + if (*cptr1 == *cptr2++) { + if (*cptr1++ == '!') { + s32 offset; + + for (offset = 0; *cptr1 != '!';) { + offset = offset * 10 + *cptr1++ - '0'; + } + *offset_result = offset; + return true; + } + } else { + while (*cptr1++ != '!') { } + while (*cptr1++ != '!') { } + if (*cptr1 == 0) + return false; + + cptr2 = catchtype + 1; + } + } + return false; + } + + while ((*cptr1 == 'P' || *cptr1 == 'R') && *cptr1 == *cptr2) { + cptr1++; + cptr2++; + + if (*cptr2 == 'C') { + if (*cptr1 == 'C') + cptr1++; + cptr2++; + } + if (*cptr1 == 'C') + return false; + + if (*cptr2 == 'V') { + if (*cptr1 == 'V') + cptr1++; + cptr2++; + } + if (*cptr1 == 'V') + return false; + } + + for (; *cptr1 == *cptr2; cptr1++, cptr2++) { + if (*cptr1 == 0) + return true; + } + + return false; +} + +class __partial_array_destructor { +private: + void* p; + size_t size; + size_t n; + ConstructorDestructor dtor; + +public: + size_t i; + + __partial_array_destructor(void* array, size_t elementsize, size_t nelements, ConstructorDestructor destructor) + { + p = array; + size = elementsize; + n = nelements; + dtor = destructor; + i = n; + } + + ~__partial_array_destructor() + { + char* ptr; + + if (i < n && dtor) { + for (ptr = (char*)p + size * i; i > 0; i--) { + ptr -= size; + DTORCALL_COMPLETE(dtor, ptr); + } + } + } +};