/*
    yamm, Yet Another Micro Monitor
    wchan.c
    Copyright (C) 1994, 1995  Riccardo Facchetti

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#if defined(linux)

#include "kversion.h"
#if !defined(linux) || (KERNEL_VERSION < 1001076)
#include <string.h>
#else
#include <linux/string.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include "yamm.h"

#define BUF 128

struct func_tab *ftab = NULL;
int ftab_size = 0;
static int success = 0;

static int check_zSystemMap(void);

static int check_zSystemMap(void)
{
	static char buffer [ BUF ];
	struct stat usr_stat, etc_stat;
	int ufd=0, efd=0;
	int ret=0;

	if (!stat(_ETC_ZSYSTEM_MAP, &etc_stat)) {
		if (!stat(_USRSRC_ZSYSTEM_MAP, &usr_stat)) {
			if (etc_stat.st_mtime < usr_stat.st_mtime) {
				ufd = open(_USRSRC_ZSYSTEM_MAP, O_RDONLY);
				efd = open(_ETC_ZSYSTEM_MAP, O_CREAT|O_WRONLY|O_TRUNC, 022);
				while ((ret=read(ufd, buffer, BUF))!=0)
					write(efd, buffer, ret);
				close(efd);
				close(ufd);
				chmod(_ETC_ZSYSTEM_MAP, 0644);
			}
		}
		return 0;
	}
	else {
		if (!stat(_USRSRC_ZSYSTEM_MAP, &usr_stat)) {
			ufd = open(_USRSRC_ZSYSTEM_MAP, O_RDONLY);
			efd = open(_ETC_ZSYSTEM_MAP, O_CREAT|O_WRONLY, 022);
			while ((ret=read(ufd, buffer, BUF))!=0)
				write(efd, buffer, ret);
			close(efd);
			close(ufd);
			chmod(_ETC_ZSYSTEM_MAP, 0644);
			return 0;
		}
		return -1;
	}
/*
 * NOT REACHED
 */
	return -1;
}

int read_ftab(void)
{
	FILE *fp;
	static char buffer [ BUF ];
	register int counter = 0;

	if (check_zSystemMap())
		return -1;

	fp = fopen (_ETC_ZSYSTEM_MAP, "r");
	if (!fp)
		return -1;

	while(fgets(buffer, BUF, fp)) {
		counter++;
		ftab = (struct func_tab *)realloc ( ftab, counter *
													sizeof(struct func_tab) );
		if (ftab == NULL)
			return -1;
		if (sscanf(buffer, "%lx %c %s",
					&ftab [ counter-1 ].start,
					&ftab [ counter-1 ].type,
					 ftab [ counter-1 ].name ) != 3) {
			free (ftab);
			return -1;
		}
/*
 * Strip first char if is equal to '_'
 */
		if (ftab[ counter-1 ].name[0] == '_')
			strcpy(ftab[ counter-1 ].name, &ftab[ counter-1 ].name[1]);

/*
 * Strip sys_ head if exist
 */
		if (!strncmp(ftab[ counter-1 ].name, "sys_", 4))
			strcpy(ftab[ counter-1 ].name, &ftab[ counter-1 ].name[4]);
	}
	counter++;
	ftab = (struct func_tab *)realloc ( ftab, counter *
													sizeof(struct func_tab) );
	memset(&ftab [ counter-1 ], 0, sizeof(struct func_tab) );
	ftab_size = counter;
	success = 1;
	return 0;
}

int search_func( unsigned long wchan )
{
	register int counter;

	if (!success)
		return -1;

	for (counter=0; ftab [ counter ].type; counter++) {
		if (ftab [ counter ].start <= wchan) {
			if (counter+1 >= ftab_size)
				return counter;
			if (ftab [ counter+1 ].start > wchan)
				return counter;
			continue;
		}
		return -1;
	}
	return -1;
}

#endif /* linux */
