/*
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 (char *s,unsigned long length)
{
if (length)
fwrite (s,1,length,stdout);
}
void ew_print_char (char c)
{
putc (c,stderr);
}
void ew_print_text (char *s,unsigned long length)
{
if (length)
fwrite (s,1,length,stderr);
}
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;
flockfile (stdin);
c=getchar_unlocked();
while (c==' ' || c=='\t' || c=='\n')
c=getchar_unlocked();
negative=0;
if (c=='+')
c=getchar_unlocked();
else
if (c=='-'){
c=getchar_unlocked();
negative=1;
}
if (!is_digit (c)){
funlockfile (stdin);
if (c!=EOF)
ungetc (c,stdin);
*i_p=0;
return 0;
}
i=c-'0';
while (c=getchar_unlocked(),is_digit (c)){
i+=i<<2;
i+=i;
i+=c-'0';
};
if (negative)
i=-i;
funlockfile (stdin);
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;
flockfile (stdin);
c=getchar_unlocked();
while (c==' ' || c=='\t' || c=='\n')
c=getchar_unlocked();
if (c=='+')
c=getchar_unlocked();
else
if (c=='-'){
s[n++]=c;
c=getchar_unlocked();
}
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_unlocked();
}
result=0;
if (digits)
if (dot==2 || ! (c=='e' || c=='E'))
result=-1;
else {
if (n<256)
s[n++]=c;
c=getchar_unlocked();
if (c=='+')
c=getchar_unlocked();
else
if (c=='-'){
if (n<256)
s[n++]=c;
c=getchar_unlocked();
}
if (is_digit (c)){
do {
if (n<256)
s[n++]=c;
c=getchar_unlocked();
} 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';
*r_p=atof (s);
}
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;
}