/*
 * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
 * COPYRIGHT(C) FUJITSU LIMITED 2001
 *
 * $Id: main.c,v 1.3 2001/11/19 22:02:09 tjm Exp $
 */
#ifndef __KERNEL__
#define __KERNEL__
#include <lcrash.h>
#include <stdio.h>
#include <linux/module.h>
#undef __KERNEL__
#else   /* __KERNEL__ */
#include <lcrash.h>
#include <stdio.h>
#include <linux/module.h>
#endif  /* __KERNEL__ */

#define	GK_LINE_LENGTH	255	/* ksyms' a line length */

#if (ARCH == ia64)
void
*kl_get_ra(void)
{
	return(0);
}
#endif


/*
 * print_ksyms()
 *
 *  This function outputs the kernel symbols
 *  of ksyms form got from a dump file.
 */
void
print_ksyms(void)
{
	syment_t *module_list_sym;	/* refer the symbol "module_list" */
	struct module *next_module;	/* modules are followed */
	struct module temp_module;	/* searching module */
	struct module_symbol temp_syms;	/* symbols are followed */
	char symbol_name[GK_LINE_LENGTH];
	char mod_name[GK_LINE_LENGTH];	/* symbol name, module name */
        int i, j;			/* loop counter */
	k_error_t gb_error;		/* GET_BLOCK result */


	kl_reset_error();

	module_list_sym = kl_lkup_symname("module_list");
	if (module_list_sym == (syment_t *)NULL) {
		KL_ERROR = KLE_NO_SYMBOLS;
		return;
	}

	/* searching module_list */
	gb_error = GET_BLOCK(module_list_sym->s_addr,
		sizeof(struct module*), (void*)&next_module);
	if (gb_error) {
		KL_ERROR = gb_error;
		return;
	}

	if (next_module == NULL) {
		KL_ERROR = KLE_INVALID_VADDR;
		return;
	}

	/* if each name longer than GK_LINE_LENGTH, can stop error*/
	mod_name[GK_LINE_LENGTH - 1] = '\0';
	symbol_name[GK_LINE_LENGTH - 1] = '\0';

	/* searching all modules (and a kernel) */
	for (;next_module != NULL; next_module = temp_module.next) {
		gb_error = GET_BLOCK((kaddr_t)next_module,
		sizeof(struct module), &temp_module);
		if (gb_error) {
			KL_ERROR = gb_error;
			return;
		}
		if (temp_module.name == NULL) {
			KL_ERROR = KLE_INVALID_VADDR;
			return;
		}
		gb_error = GET_BLOCK((kaddr_t)temp_module.name,
			sizeof(char) * (GK_LINE_LENGTH - 1), mod_name);
		if (gb_error) {
			KL_ERROR = gb_error;
			return;
		}

		gb_error = GET_BLOCK((kaddr_t)temp_module.syms,
			sizeof(struct module_symbol),
			(void*)&temp_syms);
		if (gb_error) {
			KL_ERROR = gb_error;
			return;
		}

		/* searching all symbols */
		for (i = 0; i < temp_module.nsyms; i++) {
			gb_error = GET_BLOCK((kaddr_t)&temp_module.syms[i],
				sizeof(struct module_symbol), &temp_syms);
			if (gb_error) {
				KL_ERROR = gb_error;
				return;
			}
			if (temp_syms.name == NULL)
				continue;    // need ?

			/* output */
#if (ARCH == ia64 || ARCH == alpha)
			printf("%016"FMTPTR"x ", (kaddr_t)temp_syms.value);
#elif (ARCH == i386 || ARCH == s390)
			printf("%08"FMTPTR"x ", (kaddr_t)temp_syms.value);
#endif
			j = 0;
			do {
				gb_error = GET_BLOCK((kaddr_t)&temp_syms.name[(GK_LINE_LENGTH - 1) * j],
					GK_LINE_LENGTH - 1, symbol_name);
				if (gb_error) {
					KL_ERROR = gb_error;
					return;
				}
				printf("%s", symbol_name);
				j++;
			} while (strlen(symbol_name) == (GK_LINE_LENGTH - 1));

			if (mod_name[0] != '\0') {
				/* case of a module */
				printf("\t[%s", mod_name);
				j = 1;
				while (strlen(mod_name) == (GK_LINE_LENGTH - 1)) {
					gb_error = GET_BLOCK((kaddr_t)&temp_module.name[(GK_LINE_LENGTH - 1) * j],
						GK_LINE_LENGTH - 1, mod_name);
					if (gb_error) {
						KL_ERROR = gb_error;
						return;
					}
					printf("%s", mod_name);
					j++;
				}
				printf("]");
			}
			printf("\n");
		}
	}
}

/* 
 * main()
 */
int
main(int argc, char **argv)
{
	if (argc != 4) {
		fprintf(stderr, "Usage: %s map dump kerntypes\n", argv[0]);
		exit(1);
	}

	/* Set up signal handler to handle SIGINT and to prevent lcrash
	 * from dumping core on SEGV and BUSERR signals.
	 */
	kl_sig_setup();

	kl_init_klib(argv[1], argv[2], argv[3], 1);
	if (KL_ERROR) {
		if (KL_ERROR & (KLE_OPEN_ERROR|KLE_DUMP)) {
			fprintf(KL_ERRORFP, "%s: ", argv[2]);
		} else if (KL_ERROR & 
			(KLE_OPEN_ERROR|KLE_MAP_FILE|KLE_BAD_MAP_FILE)) {
			fprintf(KL_ERRORFP, "%s: ", argv[1]);
		}
		kl_print_error();
		exit(1);
	}
	if (!STP) {
		exit(1);
	}

	/* output ksyms here */
	print_ksyms();
	if (KL_ERROR) {
		if(KL_ERROR & (KLE_NO_SYMBOLS | KLE_INVALID_VALUE))
			fprintf(KL_ERRORFP, "module_list: ");
		kl_print_error();
		exit(1);
	}

	free_temp_blocks();
	exit(0);
}




