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

#include "def.h"

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

addr_t
print_files_struct(addr)
	addr_t addr;
{
	int i, cnt;
	struct files_struct fs;
	addr_t fds[NR_OPEN_DEFAULT];

	mprintf("   CNT  MFD MFDS NEXT FILEPP\n");
	memread(addr, sizeof(fs), &fs, "files_struct");
	mprintf("   %3d %4d %4d %4d %8lx\n", fs.count.counter, fs.max_fds, fs.max_fdset, fs.next_fd, fs.fd);
	memread((addr_t)fs.fd, sizeof(fds), &fds, "file");
	cnt = 0;
	for (i = 0; i < NR_OPEN_DEFAULT && i < fs.max_fds; i++) {
		if (fds[i]) {
			mprintf("%5d:%8lx", i, fds[i]);
			cnt++;
			if (cnt >= 5) {
				cnt = 0;
				mprintf("\n");
			}
		}
	}
	mprintf("\n");
	return 0;
}

void
prhead_task()
{
	mprintf(SPTR" S   PID   SID   UID  EUID  PRI NAME             FLAGS\n",
		"ADDR");
}

addr_t
print_task(addr, full, sw)
	addr_t addr;
	int full;
	int sw;
{
	struct task_struct ts;
	char c;
	static const struct bitname tsflags[] = {
		{ PF_ALIGNWARN,	"alignwarn" },
		{ PF_STARTING,	"starting" },
		{ PF_EXITING,	"exiting" },
		{ PF_FORKNOEXEC,"noexec" },
		{ PF_SUPERPRIV,	"priv" },
		{ PF_DUMPCORE,	"dumpcore" },
		{ PF_SIGNALED,	"signaled" },
		{ PF_MEMALLOC,	"memalloc" },
		{ PF_VFORK,	"vfork" },
		{ PF_USEDFPU,	"usedpfu" },
		{ 0,		NULL }
	};

	memread(addr, sizeof(ts), &ts, "task_struct");
	mprintf(FPTR " ", addr);

	switch (ts.state) {
	case TASK_RUNNING:		c = 'R';	break;
	case TASK_INTERRUPTIBLE:	c = 'I';	break;
	case TASK_UNINTERRUPTIBLE:	c = 'U';	break;
	case TASK_ZOMBIE:		c = 'Z';	break;
	case TASK_STOPPED:		c = 'T';	break;
#ifdef TASK_SWAPPING
	case TASK_SWAPPING:		c = 'S';	break;
#endif /*TASK_SWAPPING*/
	default:			c = '?';	break;
	}
	mprintf("%c %5d %5d %5d %5d %4ld", c, ts.pid, ts.session, ts.uid, ts.euid, ts.priority);
	mprintf(" %-16s", ts.comm);
	mprintbit(tsflags, ts.flags);
	mprintf("\n");

	if (!full)
		goto out;

	print_files_struct(ts.files);
	mprintf("\texec_domain:%8lx\n", ts.exec_domain);
	mprintf("\tpptr:%8lx\n", ts.p_pptr);
	mprintf("\tu:%lx  tss:%lx\n", ts.user, &((struct task_struct *)addr)->tss);
	mprintf("\tfs_struct:%8lx  tty_struct:%8lx\n", ts.fs, ts.tty);
#if defined(ARCH_i386)
	mprintf("\teip:%lx  esp:%lx  esp0:%lx  ebp:%lx\n", ts.tss.eip, ts.tss.esp, ts.tss.esp0, ts.tss.ebp);
#endif
	mprintf("\n");

out:
	return (addr_t)ts.next_task;
}

int
getinfo_fromtask(addr, ip, sp, stack)
        addr_t addr;
        addr_t *ip, *sp, *stack;
{
        struct task_struct tsk;

        memread(addr, sizeof(tsk), &tsk, "task_struct");

#if defined(ARCH_i386)
        if (ip)
                *ip = tsk.tss.eip;
        if (sp)
                *sp = tsk.tss.esp;
#endif
        if (stack)
                *stack = addr;
        return tsk.pid;
}

addr_t
print_fs_struct(addr)
	addr_t addr;
{
	struct fs_struct fs;

	memread(addr, sizeof(fs), &fs, "fs_struct");
	mprintf("count: %d\n", fs.count.counter);
	mprintf("umask: 0%o\n", fs.umask);
	mprintf("root:  %8lx\n", fs.root);
	mprintf("pwd:   %8lx\n", fs.pwd);
	return 0;
}

addr_t
print_mm_struct(addr)
	addr_t addr;
{
	struct mm_struct mm;

	mprintf("addr: " FPTR "\n", addr);
	memread(addr, sizeof(mm), &mm, "mm_struct");

	mprintf("mmap:       " FPTR "\n", mm.mmap);
	mprintf("mmap_avl:   " FPTR "\n", mm.mmap_avl);
	mprintf("mmap_cache: " FPTR "\n", mm.mmap_cache);
	mprintf("pgd:        " FPTR "\n", mm.pgd);
	mprintf("mm_users:   %x\n", ATOMIC_READ(mm.count));
	mprintf("map_count:  %x\n", mm.map_count);
	mprintf("segments:   " FPTR "\n", mm.segments);
	return 0;
}

int
search_task(addr)
	addr_t addr;
{
	struct task_struct task;
	addr_t taddr;
	extern addr_t init_task_addr;

	if (init_task_addr == 0)
		return 0;
	taddr = init_task_addr;
	do {
		memread(taddr, sizeof(task), &task, "task_struct");
		if (addr >= taddr && addr < taddr + 2 * PAGE_SIZE) {
			mprintf("task_struct pid %d offset %lx\n",
				task.pid, addr - taddr);
			return 1;
		}
		taddr = (addr_t)task.next_task;
	} while (taddr != init_task_addr);

	return 0;	/* not found */
}
