#ident "$Header: misc.c 1.12 89/10/26 $"

/*
 * $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 */

/*
 * $Log:	misc.c,v $
 */

#ifndef lint
static char rcsid[] = "$Header: misc.c 1.12 89/10/26 $";
#endif

#include "crash.h"
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/dir.h> 
#include <sys/resource.h>	/* needed for proc.h */
#include <signal.h>
#include <sys/user.h>
#include <sys/timer.h>		/* needed for proc.h */
#include <sys/proc.h>
#include <sys/vm.h>
#ifdef CROSS
#include "/usr/include/sys/stat.h"
#else
#include <sys/stat.h>
#endif /* CROSS */
#include <sys/pte.h>
#include <sys/vmparam.h>
#include <sys/plocal.h>
#include <a.out.h>

/* #undef N_ABS		/* conflict with a.out.h and nlist.h */

/*#include <filehdr.h> */
#include <ldfcn.h>
/* #include <scnhdr.h> */
/* #include <syms.h> */
/* #include <linenum.h> */
/* #include <aouthdr.h> */

long Etext;
int disrd;
int xdebug;

cmdsum()
{
	register  struct  tsw	*tp;
	char lbuf[128];

	printf("DYNIX/ptx(R) Dump Analyzer -- Version %s of %s.\n\n", Version, Date);
	printf("available commands:\n");
	for(tp = t; tp->t_snm; tp++)
		if(tp->t_dsc) {
			if (*tp->t_snm == ' ')
				lbuf[0] = '\0';
			else
				sprintf(lbuf, "(%s)", tp->t_snm);
			printf("%s\t%s\t%s\n", lbuf, tp->t_nm, tp->t_dsc);
		}
	tok = 0;
}

nop(){}

char *
addr_str(addr)
{
	unsigned int off;
	char *symfound;
	static char buf[ MAXSTRLEN + 10 ];

	if (addr == 0)
		return("0x0");
	symfound = lookbyval(addr, &off);
	if (symfound && (off <= 0x1000)) {
		if( off )
			sprintf(buf, "%s+%#x", symfound, off);
		else
			sprintf(buf, "%s",symfound);
	} else
		sprintf(buf, "%#x", addr);
	return buf;
}

What()
{
	int  addr;
	char *arg;

	while((arg = token()) != NULL) {
		addr = atoi(arg);
		if ( err_atoi ) {
			printf("'%s', %s?\n", arg, err_atoi);
			continue;
		}
		printf("%s = %#x\n", addr_str(addr), addr);
	}
}

Vtop()
{
	int vaddr;
	int phys;
	char *arg;

	arg = token();
	vaddr = atoi(arg);
	phys = vtop(vaddr);
	printf("virt = %s, phys = %08#x\n", arg, phys);
}
	
vtop(vaddr)
int vaddr;
{
	int paddr;
	
#ifdef	i386
	if (vaddr < 8192)
		return vaddr;
#endif
	paddr = (int)((int *)Sysmap + (vaddr / NBPG));
	lseek(vmcorefd, paddr, 0);
	read(vmcorefd, &paddr, sizeof paddr);
#ifdef	ns32000
# define	PTBITS	0x1ff	/* 512 byte pages */
#endif
#ifdef	i386
# define	PTBITS	0xfff	/* 4096 byte pages */
#endif
	return (paddr & ~PTBITS) | (vaddr & PTBITS);
}

readv(vaddr, addr, nbytes)
{
	register int nbyt, nrd, n, p;
	long loc;

	nbyt = nbytes;
#if CRASH_DEBUG
	if (xdebug > 1)
		printf("readv(vaddr=%#x, addr=%#x, nbytes=%d)\n", vaddr, addr, nbytes);
#endif
	while( nbytes ) {
		p = vtop(vaddr);
		n = NBPG - vaddr % NBPG;
		nrd = nbytes > n ? n : nbytes;
/* Need to check for transfer crossing over etext */
		if (p < Etext) {	
			/* text of vmcore is trashed so read from /unix */
			loc = (long) p - text_start + text_offset;
			lseek(unixfd, (long) loc, 0); 
			n = read(unixfd, addr, nrd);
		} else {
			lseek(vmcorefd, (long) p, 0);
			n = read(vmcorefd, addr, nrd);
		}
		if( n != nrd )
			return -1;
		nbytes -= nrd;
		vaddr  += nrd;
		addr   += nrd;
	}
	return nbyt;
}

readp(paddr, addr, nbytes)
{
#ifdef	CRASH_DEBUG
	if (xdebug > 5)
		printf("readp(paddr=%#x, addr=%#x, nbytes=%d\n", paddr, addr, nbytes);
#endif
	lseek(vmcorefd, paddr, 0);
	return read(vmcorefd, addr, nbytes);
}

int	err_search;

unsigned int
search(sym)
char *sym;
{
	int val;

	err_search = 0;
	if( lookbysym(sym, &val) == FALSE ) {
		err_search = 1;
		if (debug[18])
			printf("search('%s') failed\n", sym);
		return NULL;
	}
	return val;
}

getsysmap()
{
	Sysmap = (struct pte *)search("Sysmap");
	lseek(vmcorefd, Sysmap, 0);
	read(vmcorefd, &Sysmap, sizeof Sysmap);
}

trace()
{
	char *c;

	c = token();
	if (c == NULL) {
		if (xdebug) 
			xdebug = 0;
		else
			xdebug = 1;
	} else 
		xdebug = atoi(c);
	printf("Debug trace set to %d\n", xdebug);
	tok = 0;
}

Debug()
{
	set_debug("-D");	/* any string would be ok */
	if (debug[14])
		check_dup(1);
	tok = 0;

}

char *
nice_char(c)
	register char c;
{
	static char lbuf[4];
	char lb[4];

	lbuf[0] = 0;
	if (c == 0 || c == '\t') {
		sprintf(lbuf, "%c", c);
		return (lbuf);
	}
	if (c & 0200) {
		sprintf(lbuf, "M-");
		c &= 0177;
	}
	if (c < ' ') {
		sprintf(lb, "^%c", c+'@');
		strcat(lbuf, lb);
	} else if (c == 0177) {
		strcat(lbuf, "^?");
	} else {
		sprintf(lb, "%c", c);
		strcat(lbuf, lb);
	}
	return(lbuf);
}

/*
 * coff_bin
 *
 * See if a file is a COFF format file.
 * Return values:
 *    -1   --  could not open file.
 *     0   --  file was not COFF format.
 *     1   --  file was COFF format.
 */

coff_bin(s)
	char *s;
{
	register n;
	struct stat sb;
        short magic_word;			/* header word of symfile */
	AOUTHDR ohdr;				/* optoinal header in COFF file */
	struct filehdr fh;			/* coff file header */

	n = open(s, 0);
	if (n < 0)
		return (-1);
        read(n, &magic_word, sizeof(magic_word));
        if (magic_word != I386MAGIC) {
		close(n);
		return(0);
	}
	/* catch /dev/kmem here */
	if (stat(s, &sb) < 0 || (sb.st_mode & S_IFMT) != S_IFREG) {
		close(n);
		return(0);
	}
  	lseek(n, (long) 0, 0);
	if (read(n, &fh, sizeof fh) != sizeof fh) {
		close(n);
		return (0);
	}

	close(n);
	return(1);
}

char *
user_cmd(u)
	register struct user *u;
{
	register i;
	register unsigned char *s;
	static char lbuf[3*MAXCOMLEN];

	s = (unsigned char *) u->u_comm;
	lbuf[0] = 0;
	for (i=0; i < MAXCOMLEN && s[i]; i++)
		strcat(lbuf, nice_char(s[i]));
	return lbuf;
}

Dis()
{
	char *arg;
	int addr, count, length;

	if((arg = token()) == NULL) {
		printf("symbol expected\n");
		return;
	}
	addr = atoi(arg);
	if ( err_atoi ) {
err1:		printf("'%s', %s?\n", arg, err_atoi);
		tok = 0;
		return;
	}
	if((arg = token()) == NULL) {
		count = 10;
		disrd = 0;
		goto doit;
	} else {
		count = atoi(arg);
		if ( err_atoi ) {
			goto err1;
		}
	}

	if ((arg = token()) == NULL)
		disrd = 0;	/* read virtual */
	else if (*arg == 'p')
		disrd = 1;	/* read physical */
	else if (*arg == 'v')
		disrd = 0;	/* read virtual */
doit:
	while( count -- > 0 ) {
#ifdef	ns32000
		char *p = (char *)dis32000(addr, &length);
#endif
#ifdef	i386
		char *p = (char *)dis386(addr, &length);
#endif
		printf("%-19s%s	", addr_str(addr), disrd ? "p" : "v");
		if( length ) {
			printf("%s\n", p);
			addr += length;
		} else {
			printf("%#0x\n", Disread(addr));
			addr++;
		}
	}
}

Disread(addr)
char *addr;
{
	unsigned char byte;

	if (disrd)
		readp(addr, &byte, sizeof byte);
	else
		readv(addr, &byte, sizeof byte);
	return( byte );
}
