/*
 * |-----------------------------------------------------------|
 * | Copyright (c) 1991, 1990 MIPS Computer Systems, Inc.      |
 * | All Rights Reserved                                       |
 * |-----------------------------------------------------------|
 * |          Restricted Rights Legend                         |
 * | Use, duplication, or disclosure by the Government is      |
 * | subject to restrictions as set forth in                   |
 * | subparagraph (c)(1)(ii) of the Rights in Technical        |
 * | Data and Computer Software Clause of DFARS 252.227-7013.  |
 * |         MIPS Computer Systems, Inc.                       |
 * |         950 DeGuigne Avenue                               |
 * |         Sunnyvale, California 94088-3650, USA             |
 * |-----------------------------------------------------------|
 */
#ident	"$Header: proc.c,v 1.19.1.1 92/06/24 13:26:53 marker Exp $"

/*	Copyright (c) 1984 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

/*
 * This file contains code for the crash functions:  proc, defproc.
 */

#include "crash.h"
#include "time.h"

#include <sys/cred.h>
#include <sys/evecb.h>
#include <sys/hrtcntl.h>       
#include <sys/priocntl.h>  
#include <sys/events.h>
#include <sys/hrtsys.h> 
#include <sys/session.h>
#include <sys/evsys.h>
#include <sys/user.h>
#include <sys/proc.h>
#include <sys/hrtsys.h>

extern uint Pde_pg_vr,
	    Pde_pg_g,
	    Pde_pg_n,
	    Pde_pg_m,
	    Pde_pg_lock,
	    Pde_pg_cw,
	    Pde_pg_sv;
extern int  pte_to_pfn_shift;
extern int  pfn_to_byte_shift;
extern int  rev_shift;
extern int  (*Prtlb)();

extern int active;
extern struct user *ubp;		/* pointer to the ublock */
int pregpp;

char *proc_clk[] = {
                "CLK_STD",
                "CLK_USERVIRT",
                "CLK_PROCVIRT"
};

extern int slottab_invalid;

/* get arguments for proc function */
int
getproc()
{
	int slot = -1;
	int all = 0;
	int full = 0;
	int phys = 0;
	int run = 0;
	long addr = -1;
	long arg1 = -1;
	long arg2 = -1;
	int id = -1;
	int c;
	int alarm = 0;

	char *heading = "SLOT ST  PID  PPID  PGID   SID   UID PRI CPU   EVENT  NAME           FLAGS\n";

	char *prprocalarm_hdg = "    CLOCK       TIME     INTERVAL    CMD    EI D     PREVIOUS     NEXT    \n\n";

	if(!Pregpp)
		if(!(Pregpp = symsrch("pregpp")))
			error("pregpp not found in symbol table\n");

	slottab_invalid = 1;

	optind = 1;
	while((c = getopt(argcnt,args,"aefprw:")) !=EOF) {
		switch(c) {
			case 'a' :	alarm = 1; /* new from svr4 */
					break;
			case 'e' :	all = 1;
					break;
			case 'f' :	full = 1;
					break;
			case 'w' :	redirect();
					break;
			case 'r' :	run = 1;
					break;
			case 'p' :	phys = 1;
					break;
			default  :	longjmp(syn,0);
		}
	}
	fprintf(fp,"PROC TABLE SIZE = %d\n",vbuf.v_proc);

	if(!full && !alarm)
                fprintf(fp,"%s",heading);
        if(alarm)
                fprintf(fp,"%s", prprocalarm_hdg);

	if(args[optind]) {
		all = 1;
		do {
			if(*args[optind] == '#') {
				if((id = strcon(++args[optind],'d')) == -1)
					error("\n");
				prproc(all,full,slot,id,phys,run,alarm,addr,heading);
			}
			else {
				getargs(- vbuf.v_proc,&arg1,&arg2);
				if(arg1 == -1) 
					continue;
				if(arg2 != -1) {
					if (arg1 >= 0 &&
					    arg1 < vbuf.v_proc) {
						for(slot = arg1; slot <= arg2; slot++)
							prproc(all,full,slot,id,phys,
								run,alarm,addr,heading);
					} else {
						for (addr = arg1; addr <= arg2;
						     addr = (long) (((struct proc *) addr) + 1))
							prproc(all,full,-1,id,phys,run,alarm,addr,heading);
					}
				} else {
					if(arg1 >= 0 &&
					   arg1 < vbuf.v_proc)
						slot = arg1;
					else addr = arg1;
					prproc(all,full,slot,id,phys,run,alarm,addr,heading);
				}
			}
			id = slot = addr = arg1 = arg2 = -1;
		}while(args[++optind]);
	}
	else for(slot = 0; slot < vbuf.v_proc; slot++)
		prproc(all,full,slot,id,phys,run,alarm,addr,heading);
}


/* print proc table */
int
prproc(all,full,slot,id,phys,run,alarm,addr,heading)
int all,full,slot,id,phys,run, alarm;
long addr;
char *heading;
{
	char ch,*typ;
	char cp[PSCOMSIZ+1];
	long pslot_va;
	struct proc procbuf;
	preg_t pregbuf;
	int i,j,cnt,regslot;
	extern long lseek();
	struct proc *procaddr;
	int	type = 0;
	timer_t *hrp;
	timer_t hrtbuf;
	struct cred uc;
	struct as pas;
        struct sess sess;
        struct evpd evpbuf;
	char buf[40];
	proc_t *slot_to_proc();

	 if(id != -1) {
                for(slot = 0; ; slot++) {
                        if(slot == vbuf.v_proc) {
                                fprintf(fp,"%d not valid process id\n",id);
                                return;
                        }
                        if (slot_to_pid(slot) == id) {
                                procaddr = slot_to_proc(slot);
                                break;
                        }
                }
        } else if (slot != -1)
		procaddr = slot_to_proc(slot);
	else for (slot = 0; ;slot++) { 
		if(slot == vbuf.v_proc) {
                        fprintf(fp,"%x not valid process address\n", addr);
                        return;
                }
		procaddr = slot_to_proc(slot);
		if (addr == (long)procaddr)
			break;
        }
        if (!procaddr)
                return;
	readbuf(addr,(long)procaddr,phys,-1,
                    (char *)&procbuf,sizeof procbuf,"proc table");
	if(run)
		if(!(procbuf.p_stat == SRUN || procbuf.p_stat == SONPROC))
			return;

	if (alarm) {
		while (type < 2) {
			hrp = procbuf.p_italarm[type];
			for (; hrp!=NULL; hrp=hrtbuf.hrt_next) {
				readmem((long)hrp, 1, -1, (char *)&hrtbuf,
					sizeof hrtbuf, "process alarm");
				fprintf(fp, "%s %7d %11d %7d %6d %13x %10x\n",
					proc_clk[type + 1],
                                        hrtbuf.hrt_time,
                                        hrtbuf.hrt_int,
                                        hrtbuf.hrt_cmd,
                                        hrtbuf.hrt_ecb.ecb_eid,
                                        hrtbuf.hrt_prev,
                                        hrtbuf.hrt_next);
                        }
                        type++;
		}
		return;
	}
		
	if(full)
		fprintf(fp,"%s",heading);
	switch(procbuf.p_stat) {
	case NULL:   ch = ' '; break;
	case SSLEEP: ch = 's'; break;
	case SRUN:   ch = 'r'; break;
	case SIDL:   ch = 'i'; break;
	case SZOMB:  ch = 'z'; break;
	case SSTOP:  ch = 't'; break;
	case SONPROC:  ch = 'p'; break;
	case SXBRK:  ch = 'x'; break;
	default:     ch = '?'; break;
	}
	if(slot == -1)
		fprintf(fp,"  - ");
	else fprintf(fp,"%4d",slot);
	fprintf(fp," %c %5u %5u %5u %5u %5u %3u %3u",
		ch,
		slot_to_pid(slot),
		procbuf.p_ppid,
                readpid(procbuf.p_pgidp),
                readsid(procbuf.p_sessp),
                readuid(procbuf.p_cred),
		procbuf.p_pri,
		procbuf.p_cpu);
	if(procbuf.p_stat == SONPROC)
		fprintf(fp,"          ");
	else fprintf(fp," %08lx ",procbuf.p_wchan);
	for(i = 0; i < PSCOMSIZ+2; i++)
		cp[i] = '\0';


	if(procbuf.p_stat == SZOMB)
		strcpy(cp,"zombie");
	else if(getublock(slot) == -1)
		strcpy(cp,"read err on uarea");
	else
		strcpy(cp, ubp->u_comm);
	for(i = 0; i < 8 && cp[i]; i++) {
		if(cp[i] < 040 || cp[i] > 0176) {
			strcpy(cp,"unprint");
			break;
		}
	}
	fprintf(fp,"%-14s", cp);
	fprintf(fp,"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
		procbuf.p_flag & SLOAD ? " load" : "",
		procbuf.p_flag & SSYS ? " sys" : "",
		procbuf.p_flag & SLOCK ? " lock" : "",
		procbuf.p_flag & STRC ? " trc" : "",
 		procbuf.p_flag & SNWAKE ? " nwak" : "",
 		procbuf.p_flag & SPOLL ? " poll" : "",
 		procbuf.p_flag & SPRSTOP ? " prst" : "",
 		procbuf.p_flag & SPROCTR ? " prtr" : "",
 		procbuf.p_flag & SPROCIO ? " prio" : "",
 		procbuf.p_flag & SPROPEN ? " prop" : "",
		procbuf.p_flag & SOWEUPC ? " oweupc" : "",
		procbuf.p_flag & SFIXADE ? " fixade" : "",
		(procbuf.p_flag & (SLOAD|SULOAD)) == SULOAD ? " uload" : "",
		procbuf.p_flag & SPRFORK ? " prfo" : "",
		procbuf.p_flag & SRUNLCL ? " rlcl" : "",
		procbuf.p_flag & SNOSTOP ? " nstp" : "",
                procbuf.p_flag & SPTRX ? " ptrx" : "",
                procbuf.p_flag & SASLEEP ? " aslp" : "",
                procbuf.p_flag & SUSWAP ? " uswp" : "",
                procbuf.p_flag & SNOWAIT ? " nowait" : "",
                procbuf.p_flag & SJCTL ? " jctl" : "",
                procbuf.p_flag & SVFORK ? " vfrk" : "",
                procbuf.p_flag & SSWLOCKS ? " swlk" : "",
                procbuf.p_flag & SXSTART ? " xstr" : "",
                procbuf.p_flag & SPSTART ? " pstr" : "");
	if(!full)
		return;
	readmem((long)procbuf.p_sessp,1,-1,(char *)&sess,sizeof sess,
                "session");
        fprintf(fp,"\tSession: ");
        fprintf(fp,"sid: %u, ctty: ", readsid(procbuf.p_sessp));
        if (sess.s_vp)
                fprintf(fp,"vnode(%x) maj(%4u) min(%5u)\n",
                        sess.s_vp, major(sess.s_dev), minor(sess.s_dev)
);
        else
                fprintf(fp,"-\n");
        fprintf(fp,"\tCredentials: ");
	if (procbuf.p_cred) {
		readmem((long)procbuf.p_cred,1,-1,(char *)&uc,sizeof uc,
               	 	"process credentials");
        	fprintf(fp,"uid: %u, gid: %u, real uid: %u, real gid: %u\n",
                	uc.cr_uid,
                	uc.cr_gid,
                	uc.cr_ruid,
                	uc.cr_rgid);
	} else
		fprintf(fp,"-\n");
	if (procbuf.p_as) {
		readmem((long)procbuf.p_as,1,-1,(char *)&pas,sizeof pas,
                	"process addr space");
		fprintf(fp,"\tas: %x\n", procbuf.p_as);
	} else
		fprintf(fp,"\tas: -\n");
	fprintf(fp,"\twait code: %x, wait data: %x\n",
                procbuf.p_wcode,
                procbuf.p_wdata);

 	fprintf(fp,"\ttime: %d, nice: %d, exit %d\n",
		procbuf.p_time,
		procbuf.p_nice,  
		procbuf.p_xstat);  
#ifdef V5.3.1 || _KERNEL_SVR4
	fprintf(fp,"\tsig: %x, cursig: %d, clktim: %d.%06d, suid: %d, sgid: %d, size: %d\n",
#else
	fprintf(fp,"\tsig: %x, clktim: %d.%06d, suid: %d, sgid: %d, size: %d\n",
#endif V5.3.1 || _KERNEL_SVR4
		procbuf.p_sig,
#ifdef V5.3.1
		procbuf.p_cursig,
#endif
		procbuf.p_realtimer.it_value.tv_sec,
		procbuf.p_realtimer.it_value.tv_usec,
		uc.cr_suid,
		uc.cr_sgid,
		pas.a_size);
	fprintf(fp,"\tproc: %x, parent: %x, child: %x, sibling: %x\n",
		(long)procaddr,
		procbuf.p_parent,
		procbuf.p_child,
		procbuf.p_sibling);
 	if(procbuf.p_link)
		fprintf(fp,"\tlink: %x (proc slot %d)\n",
		(long)procbuf.p_link, proc_to_slot(procbuf.p_link));
	fprintf(fp,"\tutime: %ld, stime: %ld\n",
		procbuf.p_utime,procbuf.p_stime);
	fprintf(fp,"\tepid: %d, sysid: %x, rlink: %x\n",
		procbuf.p_epid,
		procbuf.p_sysid,
		procbuf.p_rlink);
	fprintf(fp,"\tsrwchan: %d, tsegacct: %x, trace: %x, sigmask: %x,",
		procbuf.p_srwchan,
		procbuf.p_segacct,
		procbuf.p_trace,
		procbuf.p_sigmask);
	fprintf(fp,"\thold: %x\n",
		procbuf.p_hold);
	fprintf(fp, "\twhystop: %d, whatstop: %d\n",
		procbuf.p_whystop,
		procbuf.p_whatstop);

	/* now the mips stuff: */
	fprintf(fp,"\tnexttlb: %d, tlbpid: %d, fp: %d\n",
		procbuf.p_nexttlb,
		procbuf.p_tlbpid,
		procbuf.p_fp);
	(*Prtlb)(&procbuf);

	/* locate and print per process region table */

	if (pregpp == 0)
		readmem((long)Pregpp->n_value,1,slot,(char *)&pregpp,
			sizeof pregpp,"pregpp");

	if (IS_KSEG2(pas.a_region) || IS_KSEG0(pas.a_region)) {
	    fprintf(fp,"\tpreg reg#   regva  type  flags\n");
    	    for( i = 0; i < pregpp; i++) {
    		readmem((long)(pas.a_region+i),1,slot,
    		(char *)&pregbuf,sizeof pregbuf,"pregion table");
    
    		if(!pregbuf.p_reg) 
    			break;
    		fprintf(fp,"\t%4d ",i);
    		regslot = region_to_slot((long)pregbuf.p_reg);
    		if(regslot >= 0)
    			fprintf(fp,"%4d ",regslot);
    		else fprintf(fp,"  -  ");
    		fprintf(fp,"%8x ",pregbuf.p_regva);
    		switch(pregbuf.p_type) {
    			case PT_UNUSED: typ = "unusd"; break;
    			case PT_TEXT: typ = "text"; break;
    			case PT_DATA: typ = "data"; break;
    			case PT_STACK: typ = "stack"; break;
    			case PT_SHMEM: typ = "shmem"; break;
    			case PT_GR: typ = "gr"; break;
    			case PT_LIBTXT: typ = "lbtxt"; break;
    			case PT_LIBDAT: typ = "lbdat"; break;
    			default: typ = ""; break;
    		}
    		fprintf(fp,"%5s ",typ);
    		fprintf(fp,"%s\n",
    			pregbuf.p_flags & PF_RDONLY ? "rdonly" : "");
    	    }
	}
}

/*
 * print machine specific tlb stuff
 */

pr4000tlb(p)
	struct proc *p;
{
	int i;

	fprintf(fp,"\twired entries:\n\tTLBHI       PFN FLAGS\n");
	for (i = 0; i < p->p_nexttlb; i++)
		fprintf(fp,"\t%8x %6x %s%s%s%s%s%s%s\n",
			p->p_tlbhi_tbl[i],
			pte_to_pfn(p->p_tlblo_tbl[i]), 
			(p->p_tlblo_tbl[i] & Pde_pg_n)
				? "nocache " : "",
			(p->p_tlblo_tbl[i] & Pde_pg_m)
				? "mod " : "",
			(p->p_tlblo_tbl[i] & Pde_pg_vr)
				? "rvalid " : "",
			(p->p_tlblo_tbl[i] & Pde_pg_g)
				? "global " : "",
			(p->p_tlblo_tbl[i] & Pde_pg_lock)
				? "lock " : "",
			(p->p_tlblo_tbl[i] & Pde_pg_sv)
				? "svalid " : "",
			(p->p_tlblo_tbl[i] & Pde_pg_cw)
				? "cw " : "");
}

pr3000tlb(p)
	struct proc *p;
{
	int i;

	fprintf(fp,"\twired entries:\n\tTLBHI       PFN FLAGS\n");
	for (i = 0; i < p->p_nexttlb; i++)
		fprintf(fp,"\t%8x %6x %s%s%s%s%s%s%s\n",
			p->p_tlbhi_tbl[i],
			p->p_tlblo_tbl[i] >> pte_to_pfn_shift,
			(p->p_tlblo_tbl[i] & Pde_pg_n)
				? "nocache " : "",
			(p->p_tlblo_tbl[i] & Pde_pg_m)
				? "mod " : "",
			(p->p_tlblo_tbl[i] & Pde_pg_vr)
				? "rvalid " : "",
			(p->p_tlblo_tbl[i] & Pde_pg_g)
				? "global " : "",
			(p->p_tlblo_tbl[i] & Pde_pg_lock)
				? "lock " : "",
			(p->p_tlblo_tbl[i] & Pde_pg_sv)
				? "svalid " : "",
			(p->p_tlblo_tbl[i] & Pde_pg_cw)
				? "cw " : "");
}

pr6000tlb(p)
	struct proc *p;
{
	int i;

	fprintf(fp,"\tutlbline:\n\tADDR        PFN FLAGS\n");
	for (i = 0; ; i++) {
		if (!(p->p_utlbline[i] & Pde_pg_sv))
			break;
		fprintf(fp,"\t%8x %6x %s%s%s%s%s%s%s\n",
			0 - Ctob(i+1),
			p->p_utlbline[i] >> pte_to_pfn_shift,
			(p->p_utlbline[i] & Pde_pg_n)
				? "nocache " : "",
			(p->p_utlbline[i] & Pde_pg_m)
				? "mod " : "",
			(p->p_utlbline[i] & Pde_pg_vr)
				? "rvalid " : "",
			(p->p_utlbline[i] & Pde_pg_g)
				? "global " : "",
			(p->p_utlbline[i] & Pde_pg_lock)
				? "lock " : "",
			(p->p_utlbline[i] & Pde_pg_sv)
				? "svalid " : "",
			(p->p_utlbline[i] & Pde_pg_cw)
				? "cw " : "");
	}
}

/* get arguments for defproc function */
int
getdefproc()
{
	int c;
	int proc = -1;
	int reset = 0;

	optind = 1;
	while((c = getopt(argcnt,args,"cw:")) !=EOF) {
		switch(c) {
			case 'w' :	redirect();
					break;
			case 'c' :	reset = 1;
					break;
			default  :	longjmp(syn,0);
		}
	}
	if(args[optind]) 
		if((proc = strcon(args[optind],'d')) == -1)
			error("\n");
	prdefproc(proc,reset);
}

/* print results of defproc function */
int
prdefproc(proc,reset)
int proc,reset;
{

	if(reset) {
		slottab_invalid = 1;
		Procslot = getcurproc();
	} else if(proc > -1) {
		if((proc > vbuf.v_proc) || (proc < 0))
			error("%d out of range\n",proc);
		Procslot = proc;
	}
	fprintf(fp,"Procslot = %d\n",Procslot);
}


int
readuid(cred)
        struct cred *cred;
{
        struct cred cr;

        readmem((char *)cred,1,getcurproc(),(char *)&cr,sizeof(struct cred),
                "cred structure");

        return cr.cr_uid;
}

int
readsid(sessp)
        struct sess *sessp;
{
        struct sess s;

        readmem((char *)sessp,1,getcurproc(),(char *)&s,sizeof(struct sess),
                "session structure");

	if (s.s_sidp)
        	return readpid(s.s_sidp);
	else	return 0;
}

int
readpid(pidp)
        struct pid *pidp;
{
        struct pid p;

        readmem((char *)pidp,1,getcurproc(),(char *)&p,sizeof(struct pid),
                "pid structure");

        return p.pid_id;
}


