diff options
Diffstat (limited to 'scon.c')
-rw-r--r-- | scon.c | 843 |
1 files changed, 843 insertions, 0 deletions
@@ -0,0 +1,843 @@ +/* + File: scon.c + Author: John van Groningen + At: University of Nijmegen +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/time.h> +#ifdef SOLARIS +# include <unistd.h> +#endif + +#define GC_FLAGS +#ifndef SOLARIS +# define MARKING_GC +#endif +#define STACK_OVERFLOW_EXCEPTION_HANDLER +#define USE_CR2 + +#ifdef STACK_OVERFLOW_EXCEPTION_HANDLER +# include <signal.h> +# ifdef LINUX +# include <sys/resource.h> +# endif +# ifdef SOLARIS +# include <ucontext.h> +# include <procfs.h> +# endif +# include <fcntl.h> +# include <sys/mman.h> +#endif + +long min_write_heap_size; + +#define MY_PATH_MAX 1025 + +char appl_path[MY_PATH_MAX]; +char home_path[MY_PATH_MAX]; + +void set_home_and_appl_path (char *command) +{ + char *p; + int r; + + realpath (getenv ("HOME"),home_path); + +#if 1 +# ifdef SOLARIS + p=getexecname(); + if (p!=NULL){ + realpath (p,appl_path); + *strrchr (appl_path,'/')='\0'; + } else + appl_path[0]='\0'; +# else + r=readlink ("/proc/self/exe",appl_path,MY_PATH_MAX-1); + if (r>=0){ + appl_path[r]='\0'; + + p=strrchr (appl_path,'/'); + if (p!=NULL) + *p='\0'; + } else + appl_path[0]='\0'; +# endif +#else + p=strchr (command,'/'); + + if (p!=NULL){ + realpath (command,appl_path); + *strrchr (appl_path,'/')='\0'; + } else { + char *path,*file_found_p; + int colon_i; + + path=(char *)getenv("PATH"); + + file_found_p=NULL; + + while (path!=NULL && file_found_p==NULL){ + char *next,try_path[MY_PATH_MAX]; + + next=strchr (path,':'); + if (next==NULL) + colon_i=strlen(path); + else + colon_i=next-path; + + strncpy (try_path,path,colon_i); + try_path[colon_i]='\0'; + + strcat (try_path,"/"); + strcat (try_path,command); + + file_found_p=(char *)realpath (try_path,appl_path); + + path=next; + if (path!=NULL) + ++path; + } + + if (file_found_p==NULL) + *appl_path='\0'; + else + *strrchr(appl_path,'/')='\0'; + } +#endif +} + +#if defined (SOLARIS) || defined (I486) +extern long ab_stack_size,heap_size,flags; +#else +extern long stack_size,heap_size,flags; +#endif + +/* +extern long ab_stack_size=512*1024,heap_size=2048*1024,flags=8; +*/ +#ifdef MARKING_GC +extern long heap_size_multiple,initial_heap_size; +#endif + +#ifdef STACK_OVERFLOW_EXCEPTION_HANDLER +struct sigaction old_sa; + +extern int stack_overflow (void); +extern int *halt_sp; + +# ifdef LINUX +extern int *a_stack_guard_page; +int *below_stack_page; + +void *allocate_memory_with_guard_page_at_end (int size) +{ + int alloc_size; + char *p,*end_p; + + alloc_size=(size+4096+4095) & -4096; + + p=malloc (alloc_size); + if (p==NULL) + return p; + + end_p=(char*)(((int)p+size+4095) & -4096); + mprotect (end_p,4096,PROT_NONE); + + return p; +} + +# ifdef USE_CR2 +static void clean_exception_handler (int s,struct sigcontext sigcontext) +{ + if ( + (((int)sigcontext.cr2 ^ (int)below_stack_page) & -4096)==0 || + (((int)sigcontext.cr2 ^ (int)a_stack_guard_page) & -4096)==0) + { + sigcontext.eip=(int)&stack_overflow; + sigcontext.esp=(int)halt_sp; + } else { + sigaction (SIGSEGV,&old_sa,NULL); + /* + if (old_sa.sa_handler==SIG_DFL || old_sa.sa_handler==SIG_IGN) + sigaction (SIGSEGV,&old_sa,NULL); + else + old_sa.sa_sigaction (s,sigcontext); + */ + } +} +# else +static void clean_exception_handler_info (int s,struct siginfo *siginfo_p,void *p); + +static void clean_exception_handler_context (int s,struct sigcontext sigcontext) +{ + struct sigaction sa; + + sigcontext.eip=(int)&stack_overflow; + sigcontext.esp=(int)halt_sp; + + sigemptyset (&sa.sa_mask); + sa.sa_sigaction=&clean_exception_handler_info; + sa.sa_flags= SA_ONSTACK | SA_RESTART | SA_SIGINFO; + + sigaction (SIGSEGV,&sa,NULL); +} + +static void clean_exception_handler_info (int s,struct siginfo *siginfo_p,void *p) +{ + struct sigaction sa; + + if ( + (((int)siginfo_p->si_addr ^ (int)below_stack_page) & -4096)==0 || + (((int)siginfo_p->si_addr ^ (int)a_stack_guard_page) & -4096)==0) + { + struct sigaction sa; + + sigemptyset (&sa.sa_mask); + sa.sa_handler=&clean_exception_handler_context; + sa.sa_flags= SA_ONSTACK | SA_RESTART; + + sigaction (SIGSEGV,&sa,NULL); + } else { + if (old_sa.sa_handler==SIG_DFL || old_sa.sa_handler==SIG_IGN) + sigaction (SIGSEGV,&old_sa,NULL); + else + old_sa.sa_sigaction (s,siginfo_p,p); + } +} +# endif + +static void install_clean_exception_handler (void) +{ + char proc_map_file_name[64]; + int proc_map_fd,a; + struct sigaction sa; + stack_t sig_s; + int *sig_stack; + + sprintf (proc_map_file_name,"/proc/%d/maps",getpid()); + + proc_map_fd=open (proc_map_file_name,O_RDONLY); + + if (proc_map_fd<0) + return; + + for (;;){ + static char m[17]; + unsigned int b,e; + + if (read (proc_map_fd,m,17)==17 && m[8]=='-'){ + int i; + + b=0; + e=0; + for (i=0; i<8; ++i){ + int c; + + c=m[i]; + b=b<<4; + if ((unsigned)(c-'0')<10) + b+=c-'0'; + else if ((unsigned)((c & ~32)-'A')<26) + b+=(c & ~32)-('A'-10); + else + break; + + c=m[9+i]; + e=e<<4; + if ((unsigned)(c-'0')<10) + e+=c-'0'; + else if ((unsigned)((c & ~32)-'A')<26) + e+=(c & ~32)-('A'-10); + else + break; + } + + if (i==8){ + if ((unsigned)&a - (unsigned)b < (unsigned)(e-b)){ + struct rlimit rlimit; + + if (getrlimit (RLIMIT_STACK,&rlimit)==0){ + below_stack_page=(int*)((int)e-rlimit.rlim_cur-4096); + break; + } + } + continue; + } + } + + { + char c; + + c='\0'; + while (read (proc_map_fd,&c,1)==1 && c!='\n') + ; + + if (c=='\n') + continue; + } + + close (proc_map_fd); + return; + } + + close (proc_map_fd); + + sig_stack=malloc (MINSIGSTKSZ); + + if (sig_stack==NULL) + return; + + sig_s.ss_flags=0; + sig_s.ss_size=MINSIGSTKSZ; + sig_s.ss_sp=sig_stack; + + sigaltstack (&sig_s,NULL); + + sigemptyset (&sa.sa_mask); +# ifdef USE_CR2 + sa.sa_sigaction=&clean_exception_handler; + sa.sa_flags= SA_ONSTACK | SA_RESTART; +# else + sa.sa_sigaction=&clean_exception_handler_info; + sa.sa_flags= SA_ONSTACK | SA_RESTART | SA_SIGINFO; +# endif + + sigaction (SIGSEGV,&sa,&old_sa); +} +# else +# ifdef DETECT_SYSTEM_STACK_OVERFLOW +int *below_stack_page; +# endif +int *stack_guard_page; + +void *allocate_stack (int size) +{ + int alloc_size,size_a8192; + char *p,*end_p; + + size=(size+3) & -4; + size_a8192=(size+8191) & -8192; + alloc_size=8192+(size_a8192<<1)+8192; + + p=malloc (alloc_size); + if (p==NULL) + return NULL; + + end_p=(char*)(((int)p+size+8191) & -8192); + + mprotect (end_p,8192,PROT_NONE); + + stack_guard_page=(int*)end_p; + + return (void*)stack_guard_page; +} + +void clean_exception_handler (int s,struct siginfo *siginfo_p,ucontext_t *ucontext_p) +{ + struct sigaction sa; + mcontext_t *mcontext_p; + + if ( +# ifdef DETECT_SYSTEM_STACK_OVERFLOW + (((int)siginfo_p->si_addr ^ (int)below_stack_page) & -8192)==0 || +# endif + (((int)siginfo_p->si_addr ^ (int)stack_guard_page) & -8192)==0) + { + mcontext_p=&ucontext_p->uc_mcontext; +# ifdef DETECT_SYSTEM_STACK_OVERFLOW + if (mcontext_p->gwins!=NULL){ + int wi,wo,n_windows; + + n_windows=mcontext_p->gwins->wbcnt; + wo=0; + for (wi=0; wi<n_windows; ++wi){ + int *register_window_p; + + register_window_p=mcontext_p->gwins->spbuf[wi]; + if (((((int)register_window_p ^ (int)below_stack_page)) & -8192) != 0){ + /* + struct rwindow *rwindow_p; + int i; + + rwindow_p=&mcontext_p->gwins->wbuf[wi]; + for (i=0; i<8; ++i){ + register_window_p[i]=rwindow_p->rw_local[i]; + register_window_p[8+i]=rwindow_p->rw_in[i]; + } + */ + if (wi!=wo) + mcontext_p->gwins->wbuf[wo]=mcontext_p->gwins->wbuf[wi]; + ++wo; + } + } + mcontext_p->gwins->wbcnt=wo; + } +# endif + + mcontext_p->gregs[REG_PC]=(int)&stack_overflow; + mcontext_p->gregs[REG_nPC]=(int)&stack_overflow+4; + mcontext_p->gregs[REG_G5]=(int)halt_sp; + } else { + if (old_sa.sa_sigaction==SIG_DFL || old_sa.sa_sigaction==SIG_IGN) + sigaction (SIGSEGV,&old_sa,NULL); + else + old_sa.sa_sigaction (s,siginfo_p,ucontext_p); + } +} + +static void install_clean_exception_handler (void) +{ + struct sigaction sa; +# ifdef DETECT_SYSTEM_STACK_OVERFLOW + char proc_map_file_name[64]; + struct prmap prmap; + stack_t sig_s; + int proc_map_fd,a,*sig_stack; + + sprintf (proc_map_file_name,"/proc/%d/rmap",getpid()); + + proc_map_fd=open (proc_map_file_name,O_RDONLY); + + if (proc_map_fd<0) + return; + + do { + if (read (proc_map_fd,&prmap,sizeof (prmap))!=sizeof (prmap)){ + close (proc_map_fd); + return; + } + } while (! ((unsigned)&a - (unsigned)prmap.pr_vaddr < (unsigned)prmap.pr_size)); + + close (proc_map_fd); + + below_stack_page=(int*)((int)prmap.pr_vaddr-8192); + + sig_stack=malloc (MINSIGSTKSZ); + + if (sig_stack==NULL) + return; + + sig_s.ss_flags=0; + sig_s.ss_size=MINSIGSTKSZ; + sig_s.ss_sp=sig_stack; + + sigaltstack (&sig_s,NULL); +# endif + + sigemptyset (&sa.sa_mask); + sa.sa_sigaction=&clean_exception_handler; +# ifdef DETECT_SYSTEM_STACK_OVERFLOW + sa.sa_flags= SA_ONSTACK | SA_RESTART | SA_SIGINFO; +# else + sa.sa_flags= SA_RESTART | SA_SIGINFO; +# endif + + sigaction (SIGSEGV,&sa,&old_sa); +} +# endif +#endif + +void w_print_char (char c) +{ + putchar (c); +} + +void w_print_text (register char *s,unsigned long length) +{ + register int l; + + l=length; + if (l) + do { + putchar (*s); + ++s; + } while (--l); +} + +void ew_print_char (char c) +{ + putc (c,stderr); +} + +void ew_print_text (register char *s,unsigned long length) +{ + register int l; + + l=length; + if (l) + do { + putc (*s,stderr); + ++s; + } while (--l); +} + +int w_get_char() +{ + return getchar(); +} + +#define is_digit(n) ((unsigned)((n)-'0')<(unsigned)10) + +int w_get_int (int *i_p) +{ + int c,negative; + unsigned int i; + + c=getchar(); + while (c==' ' || c=='\t' || c=='\n') + c=getchar(); + + negative=0; + if (c=='+') + c=getchar(); + else + if (c=='-'){ + c=getchar(); + negative=1; + } + + if (!is_digit (c)){ + if (c!=EOF) + ungetc (c,stdin); + + *i_p=0; + return 0; + } + + i=c-'0'; + while (c=getchar(),is_digit (c)){ + i+=i<<2; + i+=i; + i+=c-'0'; + }; + + if (negative) + i=-i; + + if (c!=EOF) + ungetc (c,stdin); + + *i_p=i; + return -1; +} + +int w_get_real (double *r_p) +{ + char s[256+1]; + int c,dot,digits,result,n; + + n=0; + + c=getchar(); + while (c==' ' || c=='\t' || c=='\n') + c=getchar(); + + if (c=='+') + c=getchar(); + else + if (c=='-'){ + s[n++]=c; + c=getchar(); + } + + dot=0; + digits=0; + + while (is_digit (c) || c=='.'){ + if (c=='.'){ + if (dot){ + dot=2; + break; + } + dot=1; + } else + digits=-1; + if (n<256) + s[n++]=c; + c=getchar(); + } + + result=0; + if (digits) + if (dot==2 || ! (c=='e' || c=='E')) + result=-1; + else { + if (n<256) + s[n++]=c; + c=getchar(); + + if (c=='+') + c=getchar(); + else + if (c=='-'){ + if (n<256) + s[n++]=c; + c=getchar(); + } + + if (is_digit (c)){ + do { + if (n<256) + s[n++]=c; + c=getchar(); + } while (is_digit (c)); + + result=-1; + } + } + + if (n>=256) + result=0; + + if (c!=EOF) + ungetc (c,stdin); + + *r_p=0.0; + + if (result){ + s[n]='\0'; + if (sscanf (s,"%lg",r_p)!=1) + result=0; + } + + return result; +} + +unsigned long w_get_text (register char *string,unsigned long max_length) +{ + register int length; + + fgets (string,(int)max_length,stdin); + + for (length=0; length<max_length; ++length) + if (string[length]=='\0') + break; + + return length; +} + +void w_print_string (char *s) +{ + fputs (s,stdout); +} + +void ew_print_string (char *s) +{ + fputs (s,stderr); +} + +void w_print_int (int n) +{ + printf ("%d",n); +} + +void ew_print_int (int n) +{ + fprintf (stderr,"%d",n); +} + +void w_print_real (double r) +{ + printf ("%.15g",r); +} + +void ew_print_real (double r) +{ + fprintf (stderr,"%.15g",r); +} + +static long parse_size (register char *s) +{ + register int c; + register long n; + + c=*s++; + if (c<'0' || c>'9'){ + printf ("Digit expected in argument\n"); + exit (-1); + } + + n=c-'0'; + + while (c=*s++,c>='0' && c<='9') + n=n*10+(c-'0'); + + if (c=='k' || c=='K'){ + c=*s++; + n<<=10; + } else if (c=='m' || c=='M'){ + c=*s++; + n<<=20; + } + + if (c!='\0'){ + printf ("Error in argument\n"); + exit (-1); + } + + return n; +} + +#ifdef MARKING_GC +static long parse_integer (register char *s) +{ + register int c; + register long n; + + c=*s++; + if (c<'0' || c>'9'){ + printf ("Digit expected in argument\n"); + exit (-1); + } + + n=c-'0'; + + while (c=*s++,c>='0' && c<='9') + n=n*10+(c-'0'); + + if (c!='\0'){ + printf ("Error in integer"); + exit (-1); + } + + return n; +} +#endif + +int global_argc; +char **global_argv; + +#ifdef TIME_PROFILE +char time_profile_file_name_suffix[]=" Time Profile.pcl"; + +void create_profile_file_name (unsigned char *profile_file_name_string) +{ + char *profile_file_name; + int r; + + profile_file_name=&profile_file_name_string[8]; + + r=readlink ("/proc/self/exe",profile_file_name,MY_PATH_MAX-1); + if (r>=0){ + int length_file_name,size_time_profile_file_name_suffix; + + profile_file_name[r]='\0'; + + size_time_profile_file_name_suffix=sizeof (time_profile_file_name_suffix); + length_file_name=0; + while (profile_file_name[length_file_name]!='\0') + ++length_file_name; + + if (length_file_name+size_time_profile_file_name_suffix>MY_PATH_MAX) + length_file_name=MY_PATH_MAX-size_time_profile_file_name_suffix; + + strcat (&profile_file_name[length_file_name],time_profile_file_name_suffix); + *(unsigned int*)&profile_file_name_string[4] = length_file_name+size_time_profile_file_name_suffix-1; + } else { + strcpy (profile_file_name,&time_profile_file_name_suffix[1]); + *(unsigned int*)&profile_file_name_string[4] = sizeof (time_profile_file_name_suffix)-1; + } +} +#endif + +int execution_aborted; +int return_code; + +int main (int argc,char **argv) +{ + int arg_n; + + execution_aborted=0; + return_code=0; + +#ifdef STACK_OVERFLOW_EXCEPTION_HANDLER + install_clean_exception_handler(); +#endif + + set_home_and_appl_path (argv[0]); + + for (arg_n=1; arg_n<argc; ++arg_n){ + char *s; + + s=argv[arg_n]; + if (*s!='-') + break; + + ++s; + if (!strcmp (s,"h")){ + ++arg_n; + if (arg_n>=argc){ + printf ("Heapsize missing\n"); + return -1; + } + heap_size=parse_size (argv[arg_n]); + } else if (!strcmp (s,"s")){ + ++arg_n; + if (arg_n>=argc){ + printf ("Stacksize missing\n"); + return -1; + } +#if defined (SOLARIS) || defined (I486) + ab_stack_size=parse_size (argv[arg_n]); +#else + stack_size=parse_size (argv[arg_n]); +#endif + } else if (!strcmp (s,"b")) + flags |= 1; + else if (!strcmp (s,"sc")) + flags &= ~1; + else if (!strcmp (s,"t")) + flags |= 8; + else if (!strcmp (s,"nt")) + flags &= ~8; + else if (!strcmp (s,"gc")) + flags |= 2; + else if (!strcmp (s,"ngc")) + flags &= ~2; + else if (!strcmp (s,"st")) + flags |= 4; + else if (!strcmp (s,"nst")) + flags &= ~4; + else if (!strcmp (s,"nr")) + flags |= 16; +#ifdef MARKING_GC + else if (!strcmp (s,"gcm")) + flags |= 64; + else if (!strcmp (s,"gcc")) + flags &= ~64; + else if (!strcmp (s,"gci")){ + ++arg_n; + if (arg_n>=argc){ + printf ("Initial heap size missing\n"); + exit (-1); + } + initial_heap_size=parse_size (argv[arg_n]); + } else if (!strcmp (s,"gcf")){ + ++arg_n; + if (arg_n>=argc){ + printf ("Next heap size factor missing\n"); + exit (-1); + } + heap_size_multiple=parse_integer (argv[arg_n])<<8; + } +#endif + else + break; + } + + --arg_n; + argv[arg_n]=argv[0]; + global_argv=&argv[arg_n]; + global_argc=argc-arg_n; + + abc_main(); + + if (return_code==0 && execution_aborted!=0) + return_code= -1; + + return return_code; +} |