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

#include "def.h"

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

#include "flags_sched.h"

extern void prhead_vm_area_struct();
extern addr_t print_vm_area_struct();

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

	mprintf("   "SPTR" CNT  MFD MFDS NEXT "SPTR" "SPTR" "SPTR"\n",
		"FILE", "FD", "CLOSEXEC", "OPENFDS");
	if (addr == 0) {
		mprintf("   " SPTR "\n", "-");
		return 0;
	}

	mprintf("   " FPTR " ", addr);
	memread(addr, sizeof(files), &files, "files_struct");
	mprintf("%3x %4d %4d %4d", ATOMIC_READ(files.count), files.max_fds, files.max_fdset, files.next_fd);
	mprintf(" " FPTR " " FPTR " " FPTR "\n", files.fd, files.close_on_exec, files.open_fds);
	memread((addr_t)files.fd, sizeof(fds), &fds, "file");
	memread((addr_t)files.close_on_exec, sizeof(fd_set), &cfd, "close_on_exec");

	cnt = 0;
	for (i = 0; i < NR_OPEN_DEFAULT && i < files.max_fds; i++) {
		if (fds[i]) {
			if (cnt * (sizeof(addr_t) + 3) > 30) {
				cnt = 0;
				mprintf("\n");
			}
			if (cfd.fds_bits[__FDELT(i)] & __FDMASK(i)) {
				mprintf("%5d*" FPTR, i, (addr_t)fds[i]);
			} else {
				mprintf("%5d:" FPTR, i, (addr_t)fds[i]);
			}
			cnt++;
		}
	}
	mprintf("\n");
	return 0;
}

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

addr_t
print_task(addr, full)
	addr_t addr;
	int full;
{
	struct task_struct ts;
	char c;

	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", c, ts.pid, ts.session, ts.uid, ts.euid);
	mprintf(" " FPTR, ts.mm);
	mprintf(" %-16s", ts.comm);
	mprintbit(tsflags, ts.flags);
	mprintf("\n");

	if (!full)
		goto out;

	mprintf("\n");
	print_files_struct(ts.files);
	mprintf("\n");
	mprintf("\tfs:" FPTR "  namespace:" FPTR "\n", ts.fs, ts.namespace);
	mprintf("\tparent:" FPTR "\n", ts.parent);
	mprintf("\tuser:%lx  thread:%lx\n", ts.user, &((struct task_struct *)addr)->thread);
	mprintf("\tsig:" FPTR "  blocked:%08lx %08lx\n", ts.sig, ts.blocked.sig[0], ts.blocked.sig[1]);
	mprintf("\ttty_struct:" FPTR "\n", ts.tty);

#if defined(ARCH_i386)
	mprintf("\teip:%lx  esp:%lx  esp0:%lx\n", ts.thread.eip, ts.thread.esp, ts.thread.esp0);
#endif /*ARCH_i386*/
#if defined(ARCH_ia64)
	mprintf("\tksp:%lx  flags:%lx\n", ts.thread.ksp, ts.thread.flags);
	mprintf("\tmap_base:%lx  task_size:%lx\n", ts.thread.map_base, ts.thread.task_size);
#endif /*ARCH_ia64*/
#if defined(ARCH_ppc)
	mprintf("\tksp:%lx\n", ts.thread.ksp);
#endif /*ARCH_ppc*/
	mprintf("\n");

out:
	return (addr_t)ts.tasks.next - OFFSET(struct task_struct, tasks);
}

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.thread.eip;
	if (sp)
		*sp = tsk.thread.esp;
#endif
#if defined(ARCH_ia64) || defined(ARCH_ppc)
	if (sp)
		*sp = tsk.thread.ksp;
#endif
	if (stack)
		*stack = (addr_t)tsk.thread_info;
	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: %x\n", ATOMIC_READ(fs.count));
	mprintf("umask: 0%o\n", fs.umask);
	mprintf("root:  " FPTR "\n", fs.root);
	mprintf("pwd:   " FPTR "\n", fs.pwd);
	return 0;
}

addr_t
print_mm_struct(addr, vflag)
	addr_t addr;
	int vflag;
{
	struct mm_struct mm;

	memread(addr, sizeof(mm), &mm, "mm_struct");
	mprintf("addr:       " FPTR "\n", addr);
	mprintf("mmap:       " FPTR "\n", mm.mmap);
	mprintf("mmap_cache: " FPTR "\n", mm.mmap_cache);
	mprintf("pgd:        " FPTR "\n", mm.pgd);
	mprintf("mm_users:   %x\n", ATOMIC_READ(mm.mm_count));
	mprintf("map_count:  %x\n", mm.map_count);
	mprintf("mmlist:     " FPTR " " FPTR "\n", mm.mmlist.next, mm.mmlist.prev);

	if (vflag) {
		prhead_vm_area_struct();
		addr = (addr_t)mm.mmap;
		while (addr) {
			addr = print_vm_area_struct(addr, 0);
		}
	}
	return (addr_t)mm.mmlist.next - OFFSET(struct mm_struct, mmlist);
}

#if defined(ARCH_i386)
#define TASK_LOG_SIZE   1
#else
#define TASK_LOG_SIZE   0	/*DUMMY*/
#endif

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

	if (init_task_addr == 0)
		return 0;
	taddr = init_task_addr;
	do {
		memread(taddr, sizeof(tsk), &tsk, "task_struct");
		if (addr >= taddr && addr < taddr + sizeof(tsk)) {
			mprintf("task_struct pid %d offset %lx\n",
				tsk.pid, addr - taddr);
			return 1;
		}
		if (tsk.thread_info && addr >= (addr_t)tsk.thread_info && addr < (addr_t)tsk.thread_info + PAGE_SIZE * (1 << TASK_LOG_SIZE)) {
			mprintf("thread_info pid %d offset %lx\n",
				tsk.pid, addr - (addr_t)tsk.thread_info);
			return 1;
		}
		taddr = (addr_t)tsk.tasks.next - OFFSET(struct task_struct, tasks);
	} while (taddr != init_task_addr);

	return 0;	/* not found */
}
