/* 
 * Overwrite the Stack Overflow function to print out the address
 * of the Stack Overflow position.
 * 
 * KeiT 29.3.2004
 *
 * The Function Pointer is read back from the stack of the previous
 * called _stkhandler(). Here I assume, that the LR (Link Register)
 * has been stored on the stack + 24. This is right now only for PPC.
 * For other CPUs, you need to trace through _stkhandler to figure out
 * where the Return Address is stored.
 */


#ifndef _MPFPOWERPC
#error Only working for PPC in this way right now
#endif

#include <cglob.h>
#include <errno.h>
#include <modes.h>
#include <types.h>

const char hex[16] = "0123456789abcdef";

void x_to_a(unsigned long val, int path)
{
	char i,a,ch;
	int one;
	for (i = 24; i >= 0; i-=4)
	{
		a = val >> i;
		a &= 0x0f;
		ch = hex[a];
		one = 1;
		_os_write(path, &ch, &one);
	}
}

unsigned int strlen(char *txt)
{
	unsigned int size = 0;
	while(*txt++) size++;
	return size;
}

#define PRINT(text, val) \
{ 	cnt = strlen(text); \
	_os_write(path, text, &cnt); \
	x_to_a((unsigned long)(val),path); \
	cnt = 1; _os_writeln(path, "\n", &cnt); }

void _stkoverflow(unsigned long *newstack, unsigned long *oldstack)
{
	unsigned int cnt;
	unsigned long pc,stack;
	int path;
	error_code err;
		
#ifdef _MPFPOWERPC
	pc = oldstack[6];
#else
	pc = 0x0;
#endif
	err = _os_create("/dd/httpd_stackoverflow",FAM_WRITE|FAM_READ,&path,FAP_WRITE|FAP_READ);
	if (err)
		path = 2;	/* Can't open this file? Write to STDERR */

	PRINT("**** Stack Overflow at $", pc);
	PRINT("Stack Address ca.$",(u_int32)&stack);
	PRINT("Relativ to Module start $", pc - (unsigned long)_modhead);
	PRINT("_modhead $",_modhead);
	PRINT("_procid  $",_procid);
	PRINT("_mainid  $",_mainid);
	PRINT("_stbot   $",_stbot);
	PRINT("_sttop   $",_sttop);
	PRINT("_mtop    $",_mtop);
	PRINT("_maxstack$",_maxstack);
	PRINT("_stklimit$",_stklimit);
	_os_close(path);

	exit(EOS_STKOVF);
}
#if 1
/* Implement a complete _stkhandler with a different 
 * Stack handling and checking.
 */

/* typedef to the 1 byte unit so pointer arithmetic is easy */
typedef unsigned char byte;

static byte			 *__asm_get_stack();	/* get current stack pointer */
static void			 __asm_put_stack(byte *);	/* set current stack pointer */

static error_code stack_err;

/*
	_StkHandler()
	Checks for stack overflow. _stklimit will be set with the negative value
	of the number of bytes that the function needs. This function does not
	take too much advantage of old information in the globals because old
	stack checking code does not update it.
*/
u_int32 _stkhandler(u_int32 value)
{
	byte *sp = __asm_get_stack();		/* stack pointer */
	byte *bot = (byte *)_stbot;
	/*
		Figure out what stack limit should really be.
		This is necessary because we may have gotten here after an arbitrary
		number of calls to the old stack checking code which only modifies
		_stbot.
	*/
	
	if ( (sp - bot) < 0) {
		byte *top = (byte *)_mtop;
		if (sp <= top) {			/* overflow? */
			unsigned int cnt;
			int path;
			error_code err;
			u_int32 caller = 0;

#if defined(_MPF386)
			_asm("_stkover: mov.l 4(%ebp),%0", __obj_assign(__reg_gen(caller)));
#endif

#if defined(_MPFPOWERPC)
			_asm("_stkover: lwz %0,0(r1)\n lwz %0,4(%0)", __obj_assign(__reg_base(caller)));
#endif
			err = _os_create("/dd/httpd_stkoverflow",FAM_WRITE|FAM_READ,&path,FAP_WRITE|FAP_READ);
			if (err)
				path = 2;	/* Can't open this file? Write to STDERR */

			PRINT("**** Stack Overflow at PC $",caller);
			PRINT("Relativ to Module start $", caller - (unsigned long)_modhead);
			PRINT("Stack Address $",sp);
			PRINT("_modhead $",_modhead);
			PRINT("_procid  $",_procid);
			PRINT("_mainid  $",_mainid);
			PRINT("_stbot   $",_stbot);
			PRINT("   bot   $",bot);
			PRINT("_sttop   $",_sttop);
			PRINT("_mtop    $",_mtop);
			PRINT("  top    $",top);
			PRINT("_maxstack$",_maxstack);
			PRINT("_stklimit$",_stklimit);
			_os_close(path);

			exit(EOS_STKOVF);
		}

		_stbot = sp;

		_maxstack = (byte *)_sttop - sp;	/* reset maximum so far */
	}
	return(value);
}

static byte *__asm_get_stack(void)
{
	register byte *stack_ptr;

#if defined(_OSK) || (defined(_OS9000) && defined(_MPF68K))

	_asm("	move.l %0,%1", __reg_a7(), __reg_gen(__obj_assign(stack_ptr)));

#elif defined(_OS9000) && defined(_MPF386)

	_asm("	mov.l %0,%1", __reg_esp(), __reg_gen(__obj_assign(stack_ptr)));

#elif defined(_OS9000) && defined(_MPFPOWERPC)

	_asm("	ori %1,%0,0", __reg_r1(), __reg_gen(__obj_assign(stack_ptr)));

#else
#error No stack pointer function
#endif

	return stack_ptr;
}

static void __asm_put_stack(new_sp)
byte *new_sp;
{

#if defined(_OSK) || (defined(_OS9000) && defined(_MPF68K))

	_asm("	move.l %1,%0", __reg_a7(), __reg_gen(new_sp));

#elif defined(_OS9000) && defined(_MPF386)

	_asm("	mov.l %1,%0", __reg_esp(), __reg_gen(new_sp));

#elif defined(_OS9000) && defined(_MPFPOWERPC)

	_asm("	ori %0,%1,0", __reg_r1(), __reg_base(new_sp));

#else
#error No stack pointer function
#endif
}
#endif

/*
 * OS-9/OS-9000 implementation specific code, enhancements and modifications:
 *
 * Copyright 1991 Microware Systems Corporation
 * All Rights Reserved
 *
 * Use and/or distribution subject to terms and conditions of applicable
 * Microware license agreement(s).
 *
 * Current Version: @(#)pipe.c	2.2 12/23/91
 */

/* Corrected realloc() and optimized in dup2. KeiT 26.4.04 */

#ifndef TRUE
#define TRUE (1)
#define FALSE (0)
#endif

pthread_mutex_t io_mutex;	/* Thread Lock for starting processes */
unsigned int io_mutex_init = FALSE;
void lock_register(void *addr, int num, u_int32 caller);

error_code io_mutex_lock(int i)
{
	error_code err;
	u_int32 caller = 0;
#if defined(_MPFPOWERPC)
	_asm(" lwz %0,0(r1)\n lwz %0,4(%0)", __obj_assign(__reg_base(caller)));
#endif

	if (io_mutex_init == FALSE)
	{
		/* Init the Mutex Lock the first time */
		pthread_mutexattr_t attr;
		pthread_mutexattr_init(&attr);
		pthread_mutex_init(&io_mutex,&attr);
		io_mutex_init = TRUE;
	}
#ifdef MUTEX_LOG
	lock_register(&io_mutex, i+0x100,caller);
#endif
	err = pthread_mutex_lock(&io_mutex);
#ifdef MUTEX_LOG
	lock_register(&io_mutex, i+0x200,caller);
#endif
	return err;
}

error_code io_mutex_unlock(int i)
{
	error_code err;
	u_int32 caller = 0;
#if defined(_MPFPOWERPC)
	_asm(" lwz %0,0(r1)\n lwz %0,4(%0)", __obj_assign(__reg_base(caller)));
#endif

#ifdef MUTEX_LOG
	lock_register(&io_mutex, i+0x300,caller);
#endif
	err = pthread_mutex_unlock(&io_mutex);
	return err;
}

#define PIPESIZE 40960

int pipe(fildes)
int fildes[2];
{
	if ((fildes[0] = create("/pipe", S_ISIZE|S_IREAD|S_IWRITE, S_IREAD|S_IWRITE, PIPESIZE)) < 0)
	{
		return -1;
	}
	if ((fildes[1] = dup(fildes[0])) < 0) {
		close(fildes[0]);
		return -1;
	}
	return(0);
}



typedef struct flag_entry {
	int 	path_number;
	int		flag;
} flag_entry;


static void init_tbl(start, offset, len)
flag_entry *start;
int offset, len;
{
	int i;

	for (i=0; i<len; i++)
		start[offset+i].flag = 0;

	return;
}


#define TBL_GROW_SIZE 256

int dup2(oldd,newd)
unsigned int oldd,newd;
{
	register int i,found;
	int left=256, total=0;
	flag_entry *tab;


	if (oldd==newd) return newd;

	/* Try a simple and fast version. If we can just close and dup and the result is okay. */
	close(newd);
	i = dup(oldd);
	if (i == newd)
	{
		return i;
	}

	/* allocate and initialize initial flag table */
	tab = (flag_entry *)(malloc(sizeof(flag_entry) * TBL_GROW_SIZE));
	if (tab == NULL)
	{
		return(errno);
	}

	init_tbl(tab, 0, TBL_GROW_SIZE);

	found=-1;

	/* loop until dup returns an error (or "break"s out) */
	while ( (i = dup(oldd)) >= 0 ) {
		
		/* if this is the path number we were looking for, set */
		/* the return value and exit the loop..... we're done  */
		if (i==newd) { found=i; break; }

		/* since this wasn't the one, mark it as attempted so	*/
		/* we can get it back later								*/
		tab[total].path_number = i;
		tab[total].flag = 1;

		/* if we've used the last one, in the current allocation */
		/* block, reallocat another block, and initialize it	 */
		left--;
		total++;
		if (left <= 0) {
			tab = (flag_entry *)
					(realloc(tab, sizeof(flag_entry) * (total + TBL_GROW_SIZE)));
			init_tbl(tab, total, TBL_GROW_SIZE);
			left = TBL_GROW_SIZE;
		}
		
	}

	for (i=0; i<total; ++i) if (tab[i].flag) close(tab[i].path_number);

	free(tab);

	return found;
}

#if MUTEX_LOG

/* The following code is for logging/tracing down locks/mutex to a data module */

#include <modes.h>		/* Used for permissions */

struct lock_mutex_str {
	u_int32 count;
	void *addr;
	u_short num;
	u_short proc;
	u_int32 caller;
};

#define ANZ 32
#define PROCS 64
#define TAB_ANZ 1024
#if 0
struct data {
	int lock_mutex_act;
	int leer[2];
	struct lock_mutex_str lock_mutex_tab[ANZ];
};
#else
struct data {
	int lock_mutex_act;
	char t1[8];
	struct lock_mutex_str will[ANZ*PROCS];
	char t2[16];
	struct lock_mutex_str hat[ANZ*PROCS];
	char t3[16];
	struct lock_mutex_str lock_mutex_tab[TAB_ANZ];
};
#endif

struct data *dataptr;
u_int32 count = 0;

error_code set_datmod()
{
	char 		*dm_name = "httpd_mutex";
	mh_data 	*modptr;		/* Pointer to the data module */
	u_int16 	attrev;			/* Attribute/Revisions */
	u_int16		typlang;		/* Type/Language */
	u_int32		perm;			/* Permissions */
	error_code	error;			/* Used for error checking */

	/* Setup the att/rev and typ/lang */
	attrev = mkattrevs(MA_REENT,0);
	typlang = mktypelang(MT_DATA,ML_ANY);

	/* Setup the permissions */
	perm = MP_OWNER_READ|MP_OWNER_WRITE|MP_GROUP_READ|MP_GROUP_WRITE;

	/* Try to create the data module */
	error = _os_datmod(dm_name,		/* Name of the data module */
				sizeof(struct data),	/* Size of the data */
				&attrev,			/* Att/Rev */
				&typlang,			/* Typ/Lang */
				perm,				/* Permissions */
				(void**)&dataptr,	/* Pointer to the data */
				&modptr);			/* Module pointer */

	if(error){
		/* If error, then link to it */
		error = _os_link(&dm_name,		/* Name of the data module */
					(mh_com**)&modptr,	/* Module pointer */
					(void**)&dataptr,	/* Data pointers */
					&typlang,			/* Type/Lang */
					&attrev);			/* Att/Rev */

		if(error){
			/* If error, then exit */
			printf("Error %d linking and creating Data Module %s for Loggin.\n", error, dm_name);
			return error;
		}
	}
	
	memset(dataptr, 0, sizeof(struct data));
	strncpy(dataptr->t1, "Will----", 8);
	strncpy(dataptr->t2, "Hat ----****....", 16);
	strncpy(dataptr->t3, "Tabelle-****....", 16);
	return 0;
}

void lock_register(void *addr, int num, u_int32 caller)
{
	int index;
	int proc;
	int i,j;

	if (dataptr == 0)
		if (set_datmod() != 0)
			return;

	index = dataptr->lock_mutex_act;
	dataptr->lock_mutex_act++;
	if (dataptr->lock_mutex_act >= TAB_ANZ)
		dataptr->lock_mutex_act = 0;

	dataptr->lock_mutex_tab[index].count = count++;
	dataptr->lock_mutex_tab[index].addr = addr;
	dataptr->lock_mutex_tab[index].num = num;
	dataptr->lock_mutex_tab[index].proc = _procid;
	dataptr->lock_mutex_tab[index].caller = caller;

	dataptr->lock_mutex_tab[dataptr->lock_mutex_act].count = -1;
	dataptr->lock_mutex_tab[dataptr->lock_mutex_act].addr = (void *)0xaa55aa55;
	dataptr->lock_mutex_tab[dataptr->lock_mutex_act].num = -1;
	dataptr->lock_mutex_tab[dataptr->lock_mutex_act].proc = -1;
	dataptr->lock_mutex_tab[dataptr->lock_mutex_act].caller = -1;

	proc = _procid & (PROCS-1);	

	index = proc * ANZ;
	count++;

	if (((num & 0x300) == 0x100) || ((num & 0x3001) == 0x1001))
	{
		/* Will */
		for (i = 0; i < ANZ; i++)
		{
			if (dataptr->will[index+i].addr == addr)
			{
				return;
			}
		}
		for (i = 0; i < ANZ; i++)
		{
			if (dataptr->will[index+i].addr == 0)
			{
				dataptr->will[index+i].count = count;
				dataptr->will[index+i].addr = addr;
				dataptr->will[index+i].num = num;
				dataptr->will[index+i].proc = _procid;
				dataptr->will[index+i].caller = caller;
				break;
			}
		}
		return;
	}

	if (((num & 0x300) == 0x200) || ((num & 0x3001) == 0x1000))
	{
		/* Hat */
		for (i = 0; i < ANZ; i++)
		{
			if (dataptr->hat[index+i].addr == addr)
			{
				return;
			}
		}
		for (i = 0; i < ANZ; i++)
		{
			if (dataptr->hat[index+i].addr == 0)
			{
				break;
			}
		}
		if (i < ANZ)
		for (j = 0; j < ANZ; j++)
		{
			if (dataptr->will[index+j].addr == addr)
			{
				dataptr->hat[index+j].count = count;
				dataptr->hat[index+j].addr = addr;
				dataptr->hat[index+j].num = num;
				dataptr->hat[index+j].proc = _procid;
				dataptr->hat[index+j].caller = caller;

				dataptr->will[index+j].count = 0;
				dataptr->will[index+j].addr = 0;
				dataptr->will[index+j].num = 0;
				dataptr->will[index+j].proc = 0;
				dataptr->will[index+j].caller = 0;
				return;
			}
		}
		return;
	}

	if (((num & 0x300) == 0x300) || (num == 0x2000))
	{
		/* Frei */
		for (i = 0; i < ANZ; i++)
		{
			if (dataptr->hat[index+i].addr == addr)
			{
				dataptr->hat[index+i].count = 0;
				dataptr->hat[index+i].addr = 0;
				dataptr->hat[index+i].num = 0;
				dataptr->hat[index+i].proc = 0;
				dataptr->hat[index+i].caller = 0;
				return;
			}
		}
		return;
	}

}

#endif
