2.11BSD/src/new/crash/crashsubs.c

Compare this file to the similar file:
Show the results in this format:

/*
 *	U N I X   2 . 9 B S D   C R A S H   A N A L Y Z E R   S U B S
 *
 * More proc struct flag changes.  No progress (no effort either ;)) on
 * getting the program to compile - 1999/9/14
 *
 * Another proc struct flag went away.  Program still doesn't run or
 * compile ;-(  1999/8/11
 *
 * The proc structure flags cleaned up.  This program still doesn't run
 * (or compile) under the current system.  1997/9/2
 *
 * All the tty delay bits went away.  1997/3/28
 *
 * 'LCASE' and 'LTILDE' went away.  Some day this program should be
 * rewritten to reflect the current system.  12/9/94
 */

#include <stdio.h>
#include <sys/param.h>
#include <sys/fs.h>
#include <sys/mount.h>
#include <sys/inode.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include <pwd.h>
#include <grp.h>
#include "crash.h"

/*
 * structure to access a word as bytes
 */
struct byteof {
	char	lobyte;
	char	hibyte;
};

/* These globals are used in crash.c */
char	*subhead;			/* pntr to sub-heading */
int	line;				/* current line number */

/*
 *			S T R O C T
 *
 *	stroct		Mark Kampe	7/2/75
 *	returns:	int
 *	takes:		*char
 *	it does:	If string represents an octal integer,
 *			the value of that integer is returned.
 *			If not, a zero is returned.
 *			The string should be null terminated and
 *			contain no non-octal-numerics.
 */
int stroct(s1)
	char *s1;
{
	register char *p;
	register char thisn;
	register int value;

	p = s1;
	value = 0;
	while (thisn = *p++)
		if ((thisn >= '0') && (thisn <= '7')) {
			value <<= 3;
			value += thisn - '0';
		}
		else return(0);

	return(value);
}

/*
 *			O C T O U T
 *
 *
 *	octout		Mark Kampe	7/2/75
 *	returns:	nothing
 *	takes:		int
 *	it does:	print the integer as a six digit
 *			octal number with leading zeroes
 *			as required.  I wrote this because
 *			I found the octal output produced
 *			by printf to be very hard to read.
 *			maybe I'm a pervert, but I like the leading
 *			zeroes.  If you dont, replace this
 *			routine with "printf("%6o",arg);"
 *
 */
octout(value)
register unsigned value;
{
	char outbuf[7];
	register char *c;
	register int i;

	c = &outbuf[5];

	for(i = 0; i<6; i++) {
		*c-- = (value & 07) + '0';
		value >>= 3;
	}

	outbuf[6] = 0;		/* Null terminate string */
	printf("%s", outbuf );
	return;
}
/*
 *			L O C T O U T
 *
 *
 *	loctout		John Stewart 3 Mar 83
 *	returns:	nothing
 *	takes:		long int
 *	it does:	print the integer as an eleven digit
 *			octal number with leading zeroes
 *			as required.  (See octout, above.)
 *
 */
loctout(value)
long value;
{
	char outbuf[12];
	register char *c;
	register int i;

	c = &outbuf[10];

	for(i = 0; i<10; i++) {
		*c-- = (value & 07) + '0';
		value >>= 3;
	}
	/* no unsigned long on this machine */
	*outbuf = (value & 03) + '0';

	outbuf[11] = 0;		/* Null terminate string */
	printf("%s", outbuf );
	return;
}

hexout(value)
unsigned value;
{
	hexdump((long)value, 4);
}

hexdump(value, digs)
long value;
register int digs;
{
	char outbuf[12];
	register char *c;
	register int i;

	c = &outbuf[digs];
	*c-- = 0;		/* null terminate */
	for(; digs--;) {
		*c-- = "0123456789ABCDEF"[value & 0x0f];
		value >>= 4;
	}

	printf("%s", outbuf );
	return;
}

/*
 *			B A R F
 *
 *
 *	Print a diagnostic, flush buffers, and exit
 */
barf( c1 )
register char *c1;
{
	printf("%s\n", c1);
	exit(10);
}

/*
 *			N E W P A G E
 *
 *
 *	New page processor
 */
newpage() {
	static int	page = 0;			/* current page number */

	page++;
	line = 0;
	putchar( NEWPAGE );

	printf("\n\t\t* * * UNIX Crash Dump Analyzer * * *\t\tPage %d\n\n",
		page);
	printf("\t\t\t%s\n\n", subhead);
}


/*
 *			S H O W
 *
 *	This routine takes an address and a format type, and arranges
 * to have the value at the given address printed in the appropriate
 * format.
 *	Mike Muuss, 6/28/77.
 */

show( addr, fmt )
register unsigned *addr;
register fmt;
{
	register char *byte;
	int	i,j;

	switch( fmt ) {

	/* Special code to just return */
	case IGNORE:
		return;

	/* Octal.  Use Mark Kampe's nice routine */
	case OCT:
		octout( *addr );
		return;

	/* Long Octal.  Use John Stewart's nice routine */
	case LONGOCT:
		loctout(*(long *)addr);
		return;

	case HEXL:
		hexdump(*(long *)addr, 8);
		return;
	case HEXW:
		hexdump((long)*(int *)addr, 4);
		return;
	case HEXB:
		hexdump((long)*(char *)addr, 2);
		return;
	
	/* Interupt Address Symbolicaly */
	case TADDR:
		symbol( *addr, ISYM, 0 );
		return;
	case DADDR:
		symbol( *addr, DSYM, 0 );
		return;


	/* Decimal.  Append a dot for ease of reading */
	case DEC:
		printf("%6d.", *addr);
		return;

	/* Unsigned Decimal */
	case UDEC:
		printf("%6u.", *addr);
		return;

	/* Show both halves of the word */
	case DEV:
		printf("%2d./%2d.", ((struct byteof *)addr)->hibyte,
			(((struct byteof *)addr)->lobyte)&0377);
		return;

	/* Show the byte */
	case ONEBYTE:
		byte = (char *) addr;		/* better safe than sorry */
		printf("%6o", (*byte) & 0377 );
		return;

	/* Show printable characters */
	case CHARS:
		byte = (char *) addr;
		for( i=0; i < CBSIZE; i++ )  {
			j = *byte++ & 0377;
			if( (j<' ') || (j>'~') )
				printf("0%o", j);
			else
				putchar( j );
			putchar(' ');
		}
		return;

	/* Show the byte in decimal */
	case HALFDEC:
		byte = (char *) addr;
		j = *byte & 0377;
		printf("%d.", j);
		return;

	/* Show the long in decimal */
	case LONGDEC:
		printf("%ld.", *((long *)addr));
		return;

	/* Just in case */
	default:
		printf("I can't show that!");
		return;

	}
}

/*
 *			P U T B I T S
 *
 *	This routine accepts a table of 16 strings representing each
 * bit in a word.  For every bit set in the given word, the
 * associated message is printed.
 *	Mike Muuss, 6/28/77.
 */

putbits( array, word )
register char *array[];
register int word;
{
	register int i;			/* current bit # */

	for( i=0; i<16; i++)
		if( (word >> i) & 01 )  printf("%s", array[i] );
}

/*
 *			C O L
 *
 *	Print a region in nice columns
 *
 *	Each line is preceeded with 'indent' spaces,
 * and 8 octal values are printed on each line.  Output
 * comences at 'base' and proceeds for 'offset' words.
 */

col( indent, base, offset )
register unsigned *base;
register offset;
{
	register i;			/* Current offset */
	int	here;			/* Current line pointer */
	int	j;			/* indent counter */

	here = 50;			/* force end of line */

	for( i=0; i < offset; i++ ) {
		if( ++here >= 8 ) {
			/* End of Line */
			here = 0;
			putchar( '\n' );
			j = indent;
			while( j-- )  putchar( ' ' );
		}
		else putchar ('\t');
		octout( *( base + i ) );
	}
}


/*
 *			E Q U A L
 *
 *
 *	Determine if the first 8 characters (or up to NULL if
 * shorter than 8 chars) are equal.  True return if yes.
 */

equal( a, b )
register char *a, *b;
{
	register i;
	register wrong;

	wrong = 0;
	for( i=0; i < 8; i++ ) {
		if( !*a && !*b ) break;
		if( *a++ != *b++ )  wrong++;
	}
	if( wrong ) return( 0 );			/* mismatch */
	return( 1 );					/* match */
}


/*
 *			P R I N T S
 *
 *   This function converts the 'number' argument into decimal
 * and outprintf it at location 'pointer'.  Leading zeros are
 * suppressed.
 *	Mike Muuss, 7/8/77.
 */

char *
prints( pointer, number )
register char *pointer;
register int  number;
{
	register left;			/* whats left */

	if( left = number/10 )  pointer = prints( pointer, left );
	*pointer++ = ( number%10 ) + '0';
	*pointer = 0;			/* string terminator */
	return( pointer );
}

/*
 *			D I S P L A Y
 *
 *	This routine takes a structure of 'display' format,
 * and generates output for each element until an END element
 * is encountered.  The offset field is added to the base
 * address of each structure element, in case this routine
 * is being repeatedly called to display various structure
 * elements from the core dump.
 *	Mike Muuss, 6/27/77.
 */

display( table, offset )
register struct display *table;
register offset;
{

	while( table -> fmt ) {
		/* Display Prefix */
		printf("%s:\t", table -> msg );

		/*
		 *  Format item
		 *
		 * offset is taken to be a byte pointer
		 * place is now defined as a byte pointer
		 */
		show((unsigned *)((table->place)+offset), table->fmt);
		if (table->routine)
			(*table->routine)((table->place)+offset);
		table++;
	}
}

/*
 *	P R I N T D E V
 *
 * This routine takes a pointer to a mount structure and spins through
 * the /dev/directory look for a matching file with the same major/minor
 * numbers. It also prints out the plain file name from the super-block.
 *
 */

#define	DEVDIR "/dev"

printdev(mp)
struct mount *mp;
{
	struct stat stb;
	register struct direct *dirent;
	struct DIR *dirfd;
	char filename[20];

	dirfd = opendir(DEVDIR);
	while ((dirent = readdir(dirfd)) != NULL) {
		if (dirent->d_ino) {
			sprintf(filename, "%s/%.*s", DEVDIR,
				dirent->d_namlen, dirent->d_name);
			if (stat(filename, &stb) == 0 &&
			    (stb.st_mode & S_IFMT) == S_IFBLK &&
			    stb.st_rdev == mp->m_dev) {
				printf("\t%s\t%s\n", filename,
					mp->m_filsys.fs_fsmnt);
				break;
			}
		}
	}
	closedir(dirfd);
}

/*
 * Print a value a la the %b format of the kernel's printf
 */
printb(v, bits)
	u_long v;
	register char *bits;
{
	register int i, any = 0;
	register char c;

	if (v && bits)
		if (*bits == 8)
			printf("0%lo=", v);
		else
			if (*bits == 16)
				printf("0x%lx=", v);
			else
				putchar(' ');
	bits++;
	if (v && bits) {
		putchar('<');
		while (i = *bits++) {
			if (v & (1 << (i-1))) {
				if (any)
					putchar(',');
				any = 1;
				for (; (c = *bits) > 32; bits++)
					putchar(c);
			} else
				for (; *bits > 32; bits++)
					;
		}
		putchar('>');
	}
}

/*
 * Print out information about the PDR passed as argument
 */

char *acffld[] = {
	"non-resident",
	"read-only",
	"read-only",
	"unused",
	"read/write",
	"read/write",
	"read/write",
	"unused"
};

pdrprint(pdr)
unsigned *pdr;
{
	char plf, a, w, ed, acf;

	plf = (*pdr & 077400) >> 8;
	a = (*pdr & 0200) >> 7;
	w = (*pdr & 0100) >> 6;
	ed = (*pdr & 010) >> 3;
	acf = (*pdr & 07);
	printf(" plf: %d.%s%s%s acf: 0%o %s", plf, (a ? " A" : ""),
	      (w ? " W" : ""), (ed ? " ED" : ""), acf, acffld[acf]);
}

/*
 * Print the uid passed
 */

printuid(uid)
unsigned *uid;
{
	struct passwd *pwd, *getpwuid();

	pwd = getpwuid(*uid);
	if (pwd)
		printf("\t%s", pwd->pw_name);
}

/*
 * Print the gid passed
 */

printgid(gid)
unsigned *gid;
{
	struct group *gwd, *getgrgid();

	gwd = getgrgid(*gid);
	if (gwd)
		printf("\t%s", gwd->gr_name);
}

/*
 * Print out sinals by name.
 */

prtsig(sigm)
long *sigm;
{
#define	SIGM_FLAGS "\0\1HUP\2INT\3QUIT\4ILL\5TRAP\6IOT\7EMT\10FPE\11KILL\12BUS\13SEGV\14SYS\15PIPE\16ALRM\17TERM\20URG\21STOP\22TSTP\23CONT\24CHLD\25TTIN\26TTOU\27IO\30XCPU\31XFSZ\32VTALRM\33PROF\34WINCH\36USR1\37USR2"
	printb((u_long) *sigm, SIGM_FLAGS);
}

/*
 * Print out flags in the proc structure
 */

procflg(flgs)
int *flgs;
{
#define	PROC_FLAGS "\0\1SLOAD\2SSYS\3SLOCK\4SSWAP\5P_TRACED\6P_WAITED\7SULOCK\8P_SINTR\11SVFORK\12SVFPRNT\13SVFDONE\15P_TIMEOUT\16P_NOCLDSTOP\17P_SELECT"
	printb((u_long) *flgs, PROC_FLAGS);
}

/*
 * Print out the flags in the tty structure
 */

ttyflg(flgs)
unsigned *flgs;
{
#define	TTY_FLAGS "\0\1TANDEM\2CBREAK\4ECHO\5CRMOD\6RAW\7ODDP\10EVENP\21CRTBS\22PRTERA\23CRTERA\25MDMBUF\26LITOUT\27TOSTOP\30FLUSHO\31NOHANG\32RTSCTS\33CRTKILL\34PASS8\35CTLECH\36PENDIN\DECCTQ"
	printb((u_long) *flgs, TTY_FLAGS);
}

ttystat(flgs)
unsigned *flgs;
{
#define	TTY_STATE "\0\1TIMEOUT\2WOPEN\3ISOPEN\4FLUSH\5CARR_ON\6BUSY\7ASLEEP\10XCLUDE\11TTSTOP\12HUPCLS\13TBLOCK\14RCOLL\15WCOLL\16NBIO\17ASYNC\21BKSL\22QUOT\23ERASE\24LNCH\25TYPEN\26CNTTB"
	printb((u_long) *flgs, TTY_STATE);
}

/*
 * Ths routine prints out the flags in the buf structure
 */

bufflg(flgs)
unsigned *flgs;
{
#define	BUF_FLAGS "\0\1READ\2DONE\3ERROR\4BUSY\5PHYS\6MAP\7WANTED\10AGE\11ASYNC\12DELWRI\13TAPE\14INVAL\15bad\16RH70\17UBAREMAP\18RAMREMAP"
	printb((u_long) *flgs, BUF_FLAGS);
}

/*
 * This routine prints out the flags in the inode structure
 */

inoflg(flgs)
unsigned *flgs;
{
#define	INO_FLAGS "\0\1ILOCKED\2IUPD\3IACC\4IMOUNT\5IWANT\6ITEXT\7ICHG\10SHLOCK\11IEXLOCK\12ILWAIT\13IMOD\14IRENAME\15IPIPE\20IXMOD"
	printb((u_long) *flgs, INO_FLAGS);
}

/*
 * This routine prints out the file mode from the inode structure
 */

inomod(ip)
struct inode *ip;
{
	char special = 0;
	unsigned dev;

	show(&ip->i_mode, OCT);
	switch (ip->i_mode & IFMT) {
		case IFDIR:
				printf(" (Directory)");
				break;
		case IFCHR:
				special++;
				printf(" (Character Device)");
				break;
		case IFBLK:
				special++;
				printf(" (Block Device)");
				break;
		case IFREG:
				printf(" (Regular)");
				break;
		case IFLNK:
				printf(" (Symbolic Link)");
				break;
		case IFSOCK:
				printf(" (Socket)");
				break;
		case 0:	
				printf(" (Free-inode)");
				break;
		default:
				printf(" (Garbage!)");
				break;
	}
	if (special) {
		printf("\tdev:\t");
		dev = (unsigned) ip->i_rdev;
		show(&dev, DEV);
		putchar('\n');
	} else {
		printf("\tsize:\t");
		show(&ip->i_size, LONGDEC);
		printf("\n\t\tlastr:\t");
		show(&ip->i_lastr, LONGDEC);
		printf("\taddr[0]:\t");
		show(&ip->i_addr[0], LONGDEC);
	}
	putchar('\n');
}

/*
 * Print out the processor status in a symbolic format
 */

char *mode[] = {
	"kernel",
	"supervisor",
	"illegal",
	"user"
};

printps(ps)
unsigned ps;
{
	char curmode, prevmode, cis, prio, t, n, z, v, c;

	curmode = (ps >> 14) & 03;
	prevmode = (ps >> 12) & 03;
	cis = (ps >> 8) & 01;
	prio = (ps >> 5) & 07;
	t = (ps >> 4) & 01;
	n = (ps >> 3) & 01;
	z = (ps >> 2) & 01;
	v = (ps >> 1) & 01;
	c = ps & 01;

	printf(" <%s %s%s spl: %d.%s%s%s%s%s>", mode[curmode], mode[prevmode],
		(cis ? " CIS" : ""), prio, (t ? " T" : ""), (n ? " N" : ""),
		(z ? " Z" : ""), (v ? " V" : ""), (c ? " C" : ""));
}