/*
 * Copyright (C) 2000-2002 ASANO Masahiro
 */

#include "def.h"

#define __KERNEL__
#include <linux/module.h>

void
prhead_module()
{
	mprintf(SPTR"  SIZE CNT SYMS DEPS "SPTR" "SPTR" NAME          FLAGS\n",
		"ADDR", "INIT", "CLEANUP");
}

addr_t
print_module(addr, full)
addr_t addr;
int full;
{
	struct module m;
	char buf[32];
	static const struct bitname mflags[] = {
		{ MOD_RUNNING,		"run" },
		{ MOD_DELETED,		"deleted" },
		{ MOD_AUTOCLEAN,	"autoclean" },
		{ MOD_VISITED,		"vis" },
		{ MOD_USED_ONCE,	"u_once" },
		{ MOD_JUST_FREED,	"just_freed" },
		{ MOD_INITIALIZING,	"initializing" },
		{ 0,			0 }
	};

	memread(addr, sizeof(m), &m, "module");
	mprintf(FPTR " ", addr);
	mprintf("%5lx ", m.size);
	mprintf("%3x %4x %4x ", ATOMIC_READ(m.uc.usecount), m.nsyms, m.ndeps);
	mprintf(FPTR " " FPTR " ", m.init, m.cleanup);
	memread((addr_t)m.name, sizeof(buf), buf, "module name");
	mprintf("%-13s", buf);
	mprintbit(mflags, m.flags);
	if (m.flags == 0) {
		mprintf(" uninitialized\n");
	} else {
		mprintf("\n");
	}
	if (full) {
		mprintf("  " FPTR " " FPTR, m.ex_table_start, m.ex_table_end);
		mprintf("  " FPTR " " FPTR, m.kallsyms_start, m.kallsyms_end);
		mprintf("  " FPTR " " FPTR, m.archdata_start, m.archdata_end);
		mprintf("\n");
	}
	return (addr_t)m.next;
}

void
getmsyms_alt(addr)
	addr_t addr;
{
	int i;
	struct module m;
	struct module_symbol msym;
	char buf[256];
	int len;

	memread(addr, sizeof(m), &m, "module");
#ifdef DEBUG
	mprintf("DEBUG: getmsyms(%lx %lx)\n", addr, m.name);
#endif
	memread((addr_t)m.name, 1, buf, "module name");

	for (i = 0; i < m.nsyms; i++) {
		memread((addr_t)m.syms + sizeof(msym) * i, sizeof(msym), &msym, "module_symbol");
		if (msym.value == 0 || msym.name == 0)
			continue;
		memread((addr_t)msym.name, sizeof(buf), buf, "symbol name");
#ifdef DEBUG
		if (strchr(buf, '/') != 0)
			continue;
#endif
		len = strlen(buf);
		if (len > 10 && buf[len - 10] =='_' && buf[len - 9] == 'R')
			buf[len - 10] = 0;
#ifdef DEBUG
		mprintf(" %s=%lx\n", buf, msym.value);
#endif
		addsym(buf, msym.value, 0);
	}
}

addr_t
getmsyms(addr)
	addr_t addr;
{
	int i;
	struct module m;
	struct module_symbol msym;
	char buf[256];
	addr_t text = 0, data = 0, bss = 0;
	char path[256], *p;
	extern int strncmp();
	extern char *strstr(), *strchr(), *strcpy();

	memread(addr, sizeof(m), &m, "module");
	if (m.name == 0)
		return 0;
	memread((addr_t)m.name, 1, buf, "module name");
	if (buf[0] == 0)
		return 0;		/* maybe kernel_module */
	path[0] = 0;

	for (i = 0; i < m.nsyms; i++) {
		memread((addr_t)m.syms + sizeof(msym) * i, sizeof(msym), &msym, "module_symbol");
		if (msym.value == 0 || msym.name == 0)
			continue;
		memread((addr_t)msym.name, sizeof(buf), buf, "symbol name");
		if (strncmp(buf, "__insmod_", 9) != 0)
			continue;
#ifdef DEBUG
		mprintf("[%s]\n", buf + 9);
#endif
		if (strstr(buf, ".text")) {
			text = msym.value;
		} else if (strstr(buf, ".data")) {
			data = msym.value;
		} else if (strstr(buf, ".bss")) {
			bss = msym.value;
		} else if ((p = strchr(buf, '/'))) {
			strcpy(path, p);
			p = strstr(path, ".o_");
			if (p) p[2] = 0;
		}
	}
#ifdef DEBUG
	mprintf("%s: %x %x %x\n", path, text, data, bss);
#endif
	if (getmsyms_fromfile(path, text, data, bss)) {
		memread((addr_t)m.name, sizeof(buf), buf, "module name");
		mprintf("Error: reading module information: %s\n", buf);
		getmsyms_alt(addr);
	}
	return (addr_t)m.next;
}
