diff options
Diffstat (limited to 'mcon.c')
-rw-r--r-- | mcon.c | 382 |
1 files changed, 379 insertions, 3 deletions
@@ -7,6 +7,7 @@ #define NEW_HEADERS #define G_POWER #define FLUSH_PORT_BUFFER +#define STACK_OVERFLOW_EXCEPTION_HANDLER #ifdef MACHO # define NEWLINE_CHAR '\r' @@ -45,6 +46,170 @@ extern void sprintf (char *,...); #ifndef NEW_HEADERS # include <OSEvents.h> #endif +#ifdef STACK_OVERFLOW_EXCEPTION_HANDLER +# ifdef MACHO +# include <mach/mach.h> +# else +# include <Files.h> +# include <Folders.h> +# include <CFBundle.h> +# include <CFNumber.h> +# include <CFURL.h> +# define SIGBUS 10 +# define SIGSEGV 11 +# define SIG_DFL (void (*)())0 +# define SIG_IGN (void (*)())1 + struct sigaction { + void (*sa_handler)(); + unsigned int sa_mask; + int sa_flags; + }; + struct sigaltstack { + char *ss_sp; + int ss_size; + int ss_flags; + }; + struct sigcontext { + int sc_onstack; + int sc_mask; + int sc_ir; + int sc_psw; + int sc_sp; + void *sc_regs; + }; + struct vm_region_basic_info { + int protection; + int max_protection; + unsigned int inheritance; + int shared; + int reserved; + int offset; + int behavior; + unsigned short user_wired_count; + }; + + static CFBundleRef systemBundle=NULL; + + static int initSystemBundle (void) + { + FSRefParam fileRefParam; + FSRef fileRef; + OSErr error; + CFURLRef url; + + { + int i; + char *p; + + p=(char*)&fileRefParam; + for (i=0; i<sizeof (fileRefParam); ++i) + p[i]=0; + + p=(char*)&fileRef; + for (i=0; i<sizeof (fileRef); ++i) + p[i]=0; + } + + fileRefParam.ioNamePtr = "\pSystem.framework";; + fileRefParam.newRef = &fileRef; + + error = FindFolder (kSystemDomain,kFrameworksFolderType,false,&fileRefParam.ioVRefNum,&fileRefParam.ioDirID); + if (error!=noErr) + return 0; + + error = PBMakeFSRefSync (&fileRefParam); + if (error!=noErr) + return 0; + + url = CFURLCreateFromFSRef (NULL/*kCFAllocatorDefault*/,&fileRef); + if (url==NULL) + return 0; + + systemBundle = CFBundleCreate(NULL/*kCFAllocatorDefault*/, url); + if (systemBundle==NULL) + return 0; + + CFRelease (url); + + return 1; + } + + static int (*sigaction_p) (int,void *,void *)=NULL; + + static int sigaction (int a1,void *a2,void *a3) + { + if (sigaction_p==NULL){ + if (systemBundle==NULL) + initSystemBundle(); + sigaction_p = (int(*)(int,void*,void*)) CFBundleGetFunctionPointerForName (systemBundle,CFSTR ("sigaction")); + if (sigaction_p==NULL) + return -1; + } + + return call_function_3 (a1,a2,a3,sigaction_p); + } + + static int (*sigaltstack_p) (void *,void *); + + int sigaltstack (void *a1,void *a2) + { + if (sigaltstack_p==NULL){ + if (systemBundle==NULL) + initSystemBundle(); + sigaltstack_p = (int(*)(void*,void*)) CFBundleGetFunctionPointerForName (systemBundle,CFSTR ("sigaltstack")); + if (sigaltstack_p==NULL) + return -1; + } + + return call_function_2 (a1,a2,sigaltstack_p); + } + + static int (*mach_task_self_p) (void)=NULL; + + int mach_task_self (void) + { + if (mach_task_self_p==NULL){ + if (systemBundle==NULL) + initSystemBundle(); + mach_task_self_p = (int(*)(void)) CFBundleGetFunctionPointerForName (systemBundle,CFSTR ("mach_task_self")); + if (mach_task_self_p==NULL) + return -1; + } + + return call_function_0 (mach_task_self_p); + } + + static int (*vm_region_p) (int,void*,void *,int,void *,void *,void *); + + int vm_region (int a1,void *a2,void *a3,int a4,void *a5,void *a6,void *a7) + { + if (vm_region_p==NULL){ + if (systemBundle==NULL) + initSystemBundle(); + vm_region_p = (int(*)(int,void*,void *,int,void *,void *,void *)) CFBundleGetFunctionPointerForName (systemBundle,CFSTR ("vm_region")); + if (vm_region_p==NULL) + return -1; + } + + return call_function_7 (a1,a2,a3,a4,a5,a6,a7,vm_region_p); + } + + static int (*vm_protect_p) (int,int,int,int,int); + + int vm_protect (int a1,int a2,int a3,int a4,int a5) + { + if (vm_protect_p==NULL){ + if (systemBundle==NULL) + initSystemBundle(); + vm_protect_p = (int(*)(int,int,int,int,int)) CFBundleGetFunctionPointerForName (systemBundle,CFSTR ("vm_protect")); + if (vm_protect_p==NULL) + return -1; + } + + return call_function_5 (a1,a2,a3,a4,a5,vm_protect_p); + } +# endif +#endif #ifdef MACOSX # undef GetWindowPort @@ -1424,6 +1589,214 @@ extern void my_pointer_glue (void (*function) (void)); int execution_aborted; +#ifdef STACK_OVERFLOW_EXCEPTION_HANDLER +int *a_stack_guard_page,*b_stack_guard_page; + +void *allocate_a_stack (int size) +{ + int alloc_size; + char *p,*end_p; + + alloc_size=(size+4096+4095) & -4096; + +# ifdef MACHO + p=malloc (alloc_size); +# else + p=NewPtr (alloc_size); +# endif + if (p==NULL) + return NULL; + + end_p=(char*)(((int)p+size+4095) & -4096); + + vm_protect (mach_task_self(),(int)end_p,4096,0,0); + + a_stack_guard_page=(int*)end_p; + + return (void*)((int)end_p-size); +} + +extern int *halt_sp; +extern void stack_overflow (void); + +struct sigaction old_BUS_sa,old_SEGV_sa; + +static void clean_exception_handler (int sig,void *sip,struct sigcontext *scp) +{ + struct sigaction *old_sa_p; + unsigned int instruction; + int *registers,a; + + instruction=*(unsigned int*)(scp->sc_ir); + registers = &((int *)scp->sc_regs)[2]; + + switch (instruction>>26){ + case 36: /* stw */ case 37: /* stwu */ + case 38: /* stb */ case 39: /* stbu */ + case 44: /* sth */ case 45: /* sthu */ + case 47: /* stmw */ + case 54: /* stfd */ case 55: /* stfdu */ + { + int reg_a,a_aligned_4k; + + reg_a=(instruction>>16) & 31; + a=(short)instruction; + if (reg_a) + a+=registers[reg_a]; + + a_aligned_4k = (int)a & -4096; + + if (a_aligned_4k==(int)b_stack_guard_page || a_aligned_4k==(int)a_stack_guard_page){ + scp->sc_ir = (int)&stack_overflow; + registers[1]=(int)halt_sp; + return; + } + } + } + + old_sa_p = sig==SIGBUS ? &old_BUS_sa : &old_SEGV_sa; + + if (old_sa_p->sa_handler==SIG_DFL || old_sa_p->sa_handler==SIG_IGN) + sigaction (sig,old_sa_p,NULL); + else +# ifdef MACHO + old_sa_p->sa_handler (sig,sip,scp); +# else + call_function_3 (sig,sip,scp,old_sa_p->sa_handler); +# endif +} + +# ifndef MACHO +extern int *get_TOC (void); +# endif + +static void install_clean_exception_handler (void) +{ + { + struct vm_region_basic_info vm_region_info; +# ifdef MACHO + vm_address_t vm_address,previous_address; + mach_msg_type_number_t info_count; + memory_object_name_t object_name; + vm_size_t vm_size; +# else + int vm_address,previous_address; + int info_count; + int object_name; + int vm_size; + int *stack_top; +# endif + int r,var_on_stack; + + vm_address=(int)&var_on_stack; + + info_count=sizeof (vm_region_info); +# ifdef MACHO + r=vm_region (mach_task_self(),&vm_address,&vm_size,VM_REGION_BASIC_INFO,(vm_region_info_t)&vm_region_info,&info_count,&object_name); +# else + r=vm_region (mach_task_self(),&vm_address,&vm_size,10,(void*)&vm_region_info,&info_count,&object_name); +# endif + if (r!=0) + return; + +#ifndef MACHO + stack_top=(int*)(vm_address+vm_size); +#endif + + do { + previous_address=vm_address; + vm_address=vm_address-1; + + info_count=sizeof (vm_region_info); +# ifdef MACHO + r=vm_region (mach_task_self(),&vm_address,&vm_size,VM_REGION_BASIC_INFO,(vm_region_info_t)&vm_region_info,&info_count,&object_name); +# else + r=vm_region (mach_task_self(),&vm_address,&vm_size,10,(void*)&vm_region_info,&info_count,&object_name); +# endif + } while (vm_address!=previous_address && r==0); + + b_stack_guard_page=(int*)((int)previous_address-4096); + +#ifndef MACHO + { + int stack_size_aligned_4k; + + stack_size_aligned_4k = (stack_size+4095) & -4096; + if ((unsigned int)b_stack_guard_page < (unsigned int)((int)stack_top-stack_size_aligned_4k-4096)){ + b_stack_guard_page=(int*)((int)stack_top-stack_size_aligned_4k-4096); + vm_protect (mach_task_self(),(int)b_stack_guard_page,4096,0,0); + } + } +#endif + } + + { + struct sigaltstack sa_stack; + void *signal_stack; + struct sigaction sa; + +# ifdef MACHO + signal_stack=(int*)malloc (MINSIGSTKSZ); +# else + signal_stack=(int*)NewPtr (8192); +# endif + if (signal_stack!=NULL){ +# ifndef MACHO + int *handler_trampoline; +# endif + + sa_stack.ss_sp=signal_stack; +# ifdef MACHO + sa_stack.ss_size=MINSIGSTKSZ; +# else + sa_stack.ss_size=8192; +# endif + sa_stack.ss_flags=0; + + sigaltstack (&sa_stack,NULL); + +# ifdef MACHO + sa.sa_handler=&clean_exception_handler; + sigemptyset (&sa.sa_mask); + sa.sa_flags=SA_ONSTACK;//SA_SIGINFO; +# else + handler_trampoline = (int*) NewPtr (24); + if (handler_trampoline!=NULL){ + int *handler_address,*toc_register; + + handler_address=*(int**)&clean_exception_handler; + toc_register=get_TOC(); + +# define i_dai_i(i,rd,ra,si)((i<<26)|((rd)<<21)|((ra)<<16)|((unsigned short)(si))) +# define addis_i(rd,ra,si) i_dai_i (15,rd,ra,si) +# define addi_i(rd,ra,si) i_dai_i (14,rd,ra,si) +# define lis_i(rd,si) addis_i (rd,0,si) +# define bctr_i() ((19<<26)|(20<<21)|(528<<1)) +# define mtspr_i(spr,rs) ((31<<26)|((rs)<<21)|(spr<<16)|(467<<1)) +# define mtctr_i(rs) mtspr_i (9,rs) + + handler_trampoline[0]=lis_i (6,((int)handler_address-(short)handler_address)>>16); + handler_trampoline[1]=addi_i (6,6,(short)handler_address); + handler_trampoline[2]=mtctr_i (6); + handler_trampoline[3]=lis_i (2,((int)toc_register-(short)toc_register)>>16); + handler_trampoline[4]=addi_i (2,2,(short)toc_register); + handler_trampoline[5]=bctr_i(); + + __icbi (handler_trampoline,0); + __icbi (handler_trampoline,20); + + sa.sa_handler=(void(*)())handler_trampoline; + sa.sa_mask=0; + sa.sa_flags=1; + } +# endif + sigaction (SIGSEGV,&sa,&old_SEGV_sa); + sigaction (SIGBUS,&sa,&old_BUS_sa); + } + } +} +#endif + int main (void) { Handle stack_handle,font_handle; @@ -1452,6 +1825,10 @@ int main (void) heap_size=(stack_p[2]+7) & ~7; flags=stack_p[3]; +#ifdef STACK_OVERFLOW_EXCEPTION_HANDLER + install_clean_exception_handler(); +#endif + #ifdef SIMULATE n_processors=stack_p[1]; if (n_processors<1) @@ -1484,6 +1861,7 @@ int main (void) #endif font_id=-1; + font_handle=GetResource ('Font',128); if (font_handle!=NULL){ @@ -1503,8 +1881,6 @@ int main (void) if (!init_terminal()) return 1; -/* srand (TickCount()); */ - #ifdef G_POWER wait_next_event_available=1; #else @@ -1587,7 +1963,7 @@ int main (void) return 0; } -#ifdef TIME_PROFILE +#if defined (TIME_PROFILE) || defined (MACHO) void create_profile_file_name (unsigned char *profile_file_name) { unsigned char *cur_ap_name,*end_profile_file_name; |