[comp.os.minix] profil system call implementation 2/2

veench@cs.vu.nl (Veen van CH) (03/03/88)

In this article and the preceding article is an implementation of the
profil system call for PC-MINIX.  All diffs are relative to MINIX 1.2.
See the README file and man pages for more information.

				Dick van Veen
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	lib/a.out.h
#	lib/end.s
#	lib/make
#	lib/monitor.c
#	lib/monstart.c
#	lib/mrtso.s
#	lib/profil.c
#	man/ast.doc
#	man/nm.doc
#	man/prof.doc
#	man/strip.doc
#	src/ast.c
#	src/cc1.1.c.diff
#	src/cc1.2.c.diff
#	src/nm.c
#	src/prof.c
#	src/strip.c
# This archive created: Wed Mar 02 09:02:13 1988
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'lib/a.out.h'" '(3646 characters)'
if test -f 'lib/a.out.h'
then
	echo shar: "will not over-write existing file 'lib/a.out.h'"
else
cat << \SHAR_EOF > 'lib/a.out.h'
/* a.out header file */

struct	exec {			/* a.out header */
	unsigned char	a_magic[2];	/* magic number */
	unsigned char	a_flags;	/* flags, see below */
	unsigned char	a_cpu;		/* cpu id */
	unsigned char	a_hdrlen;	/* length of header */
	unsigned char	a_unused;	/* reserved for future use */
	unsigned short	a_version;	/* version stamp */	
				/* not used */
	long		a_text;		/* size of text segement in bytes */
	long		a_data;		/* size of data segment in bytes */
	long		a_bss;		/* size of bss segment in bytes */
	long		a_no_entry;	/* in fact: entry point, a_entry */
	long		a_total;	/* total memory allocated */
	long		a_syms;		/* size of symbol table */
				/* SHORT FORM ENDS HERE */
	long		a_trsize;	/* text relocation size */
	long		a_drsize;	/* data relocation size */
	long		a_tbase;	/* text relocation base */
	long		a_dbase;	/* data relocation base */
};

#define A_MAGIC0	(unsigned char) 0x01
#define A_MAGIC1	(unsigned char) 0x03
#define BADMAG(X)	((X).a_magic[0] != A_MAGIC0 ||\
			 (X).a_magic[1] != A_MAGIC1)

/* CPU Id of TARGET machine */
	/* byte order coded in low order two bits */
#define A_NONE	0x00	/* unknown */
#define A_I8086	0x04	/* intel i8086/8088 */
#define A_M68K	0x0B	/* motorola m68000 */
#define A_NS16K	0x0C	/* national semiconductor 16032 */

#define A_BLR(cputype)	((cputype&0x01)!=0) /* TRUE if bytes left-to-right */
#define A_WLR(cputype)	((cputype&0x02)!=0) /* TRUE if words left-to-right */

/* flags: */
#define A_EXEC	0x10	/* executable */
#define A_SEP	0x20	/* separate I/D */
#define A_PURE	0x40	/* pure text */		/* not used */
#define A_TOVLY	0x80	/* text overlay */	/* not used */

/* offsets of various things: */
#define A_MINHDR	32
#define	A_TEXTPOS(X)	((long)(X).a_hdrlen)
#define A_DATAPOS(X)	(A_TEXTPOS(X) + (X).a_text)
#define	A_HASRELS(X)	((X).a_hdrlen > (unsigned char) A_MINHDR)
#define A_HASEXT(X)	((X).a_hdrlen > (unsigned char) (A_MINHDR +  8))
#define A_HASLNS(X)	((X).a_hdrlen > (unsigned char) (A_MINHDR + 16))
#define A_HASTOFF(X)	((X).a_hdrlen > (unsigned char) (A_MINHDR + 24))
#define A_TRELPOS(X)	(A_DATAPOS(X) + (X).a_data)
#define A_DRELPOS(X)	(A_TRELPOS(X) + (X).a_trsize)
#define A_SYMPOS(X)	(A_TRELPOS(X) + (A_HASRELS(X) ? \
				((X).a_trsize + (X).a_drsize) : 0))

struct reloc {
	long		r_vaddr;	/* virtual address of reference */
	unsigned short	r_symndx;	/* internal segnum or extern symbol num */
	unsigned short	r_type;		/* relocation type */
};

/* r_tyep values: */
#define R_ABBS		0
#define R_RELLBYTE	2
#define R_PCRBYTE	3
#define R_RELWORD	4
#define R_PCRWORD	5
#define R_RELLONG	6
#define R_PCRLONG	7
#define R_REL3BYTE	8
#define R_KBRANCHE	9

/* r_symndx for internal segments */
#define S_ABS		((unsigned short)-1)
#define S_TEXT		((unsigned short)-2)
#define S_DATA		((unsigned short)-3)
#define S_BSS		((unsigned short)-4)

struct nlist {			/* symbol table entry */
	char	 	n_name[8];	/* symbol name */
	long	 	n_value;	/* value */
	unsigned char	n_sclass;	/* storage class */
	unsigned char	n_numaux;	/* number of auxiliary entries */
						/* not used */
	unsigned short	n_type;		/* language base and derived type */
						/* not used */
};

/* low bits of storage class (section) */
#define	N_SECT		  07	/* section mask */
#define N_UNDF		  00	/* undefined */
#define N_ABS		  01	/* absolute */
#define N_TEXT		  02	/* text */
#define N_DATA		  03	/* data */
#define	N_BSS		  04	/* bss */
#define N_COMM		  05	/* (common) */

/* high bits of storage class */
#define N_CLASS		0370	/* storage class mask */
#define C_NULL
#define C_EXT		0020	/* external symbol */
#define C_STAT		0030	/* static */
	/* there are many others, but they are not supported */
SHAR_EOF
fi
echo shar: "extracting 'lib/end.s'" '(119 characters)'
if test -f 'lib/end.s'
then
	echo shar: "will not over-write existing file 'lib/end.s'"
else
cat << \SHAR_EOF > 'lib/end.s'
.globl endtext, enddata, endbss, _etext, _end, _edata
.text
endtext:
_etext:
.data
enddata:
_edata:
.bss
endbss:
_end:
SHAR_EOF
fi
echo shar: "extracting 'lib/make'" '(1552 characters)'
if test -f 'lib/make'
then
	echo shar: "will not over-write existing file 'lib/make'"
else
cat << \SHAR_EOF > 'lib/make'
ar a libc.a qsort.s popen.s system.s cleanup.s fgets.s fprintf.s puts.s
ar a libc.a scanf.s monstart.s monitor.s profil.s
ar a libc.a fputs.s fread.s freopen.s fclose.s fopen.s fseek.s fflush.s
ar a libc.a ftell.s fwrite.s gets.s getc.s printdat.s setbuf.s sprintf.s
ar a libc.a doprintf.s putc.s ungetc.s strcmp.s access.s chdir.s chmod.s
ar a libc.a chown.s chroot.s creat.s dup.s dup2.s exec.s exit.s
ar a libc.a fork.s isatty.s fstat.s getegid.s getenv.s geteuid.s getgid.s
ar a libc.a getpass.s close.s getuid.s ioctl.s kill.s link.s lseek.s
ar a libc.a malloc.s brk.s brk2.s brksize.s mknod.s mktemp.s getpid.s
ar a libc.a mount.s open.s perror.s pipe.s prints.s read.s setgid.s
ar a libc.a setuid.s sleep.s alarm.s pause.s signal.s catchsig.s stat.s
ar a libc.a stime.s strcat.s strcpy.s strlen.s strncat.s strncmp.s strncpy.s
ar a libc.a sync.s time.s times.s umask.s umount.s unlink.s utime.s
ar a libc.a wait.s stderr.s write.s syslib.s call.s atoi.s message.s
ar a libc.a sendrec.s printk.s abort.s itoa.s stb.s abs.s atol.s
ar a libc.a ctype.s index.s bcopy.s getutil.s rand.s rindex.s setjmp.s
# now the compiler routines
ar a libc.a adi.s and.s cii.s cms.s cmu4.s com.s csa2.s 
ar a libc.a csb2.s cuu.s _dup.s dvi4.s dvu4.s exg.s fakfp.s 
ar a libc.a gto.s iaar.s ilar.s inn.s ior.s isar.s lar2.s 
ar a libc.a loi.s mli4.s mon.s nop.s rck.s rmi4.s rmu4.s 
ar a libc.a sar2.s sbi.s set.s sti.s strhp.s xor.s error.s 
ar a libc.a unknown.s fat.s trp.s stop.s ret6.s ret8.s lfr6.s 
ar a libc.a lfr8.s retarea.s blm.s vars.s return.s cmi4.s

SHAR_EOF
fi
echo shar: "extracting 'lib/monitor.c'" '(940 characters)'
if test -f 'lib/monitor.c'
then
	echo shar: "will not over-write existing file 'lib/monitor.c'"
else
cat << \SHAR_EOF > 'lib/monitor.c'
struct profhdr {
	int *lowpc;
	int *highpc;
	int nfunc;
};

struct cnt {
	int *pc;
	long ncall;
};

monitor(lowpc, highpc, buf, bufsiz, nfunc)
char *lowpc, *highpc;
int *buf, bufsiz, nfunc;
{
/* Use first two words in buffer for lowpc and highpc. */
	static int *sbuf, sbufsiz;
	long tmp;
	int *tmpptr = (int *) &tmp;
	int fd, scale;

	if (lowpc == 0) {
		profil(0, 0, 0, 0);
		fd = creat("mon.out", 0666);
		write(fd, sbuf, sbufsiz);
		close(fd);
		return;
	}
	sbuf = buf;
	sbufsiz = bufsiz << 1;

	buf[0] = (int) lowpc;
	buf[1] = (int) highpc;
	buf[2] = nfunc;

	scale = sizeof(struct profhdr) + nfunc*sizeof(struct cnt);
	bufsiz -= scale >> 1;
	buf    = (int *) (((int) buf) + scale);

	if (bufsiz <= 0) return;
	scale = (highpc - lowpc) >> 1;		/* use integers */
	if (scale > bufsiz) {
		tmpptr[0] = 0;
		tmpptr[1] = bufsiz;
		tmp = (tmp / scale);
		scale = tmpptr[0];
	} else	scale = 0xFFFF;
	profil(buf, bufsiz << 1, lowpc, scale);
}
SHAR_EOF
fi
echo shar: "extracting 'lib/monstart.c'" '(527 characters)'
if test -f 'lib/monstart.c'
then
	echo shar: "will not over-write existing file 'lib/monstart.c'"
else
cat << \SHAR_EOF > 'lib/monstart.c'
#define NCOUNTS		0	/* no support yet */

struct profhdr {
	int *lowpc;
	int *highpc;
	int nfunc;
};

struct cnt {
	int *pc;
	long ncall;
};

monstartup(lowpc, highpc)
int (*lowpc)(), (*highpc)();
{
	unsigned int size;
	char *buf, *sbrk();

	size = (((unsigned int) highpc - (int) lowpc + 7) & ~7) << 1;
	size += NCOUNTS * sizeof(struct cnt) + sizeof(struct profhdr);
	buf = sbrk(size);
	if ((int) buf == -1) {
		write(2, "can't allocate monitor buffer\n", 30);
		return;
	}
	monitor(lowpc, highpc, buf, size >> 1, NCOUNTS);
}

SHAR_EOF
fi
echo shar: "extracting 'lib/mrtso.s'" '(1077 characters)'
if test -f 'lib/mrtso.s'
then
	echo shar: "will not over-write existing file 'lib/mrtso.s'"
else
cat << \SHAR_EOF > 'lib/mrtso.s'
| This is the C run-time start-off routine.  It's job is to take the
| arguments as put on the stack by EXEC, and to parse them and set them up the
| way _main expects them.

.globl _main, _exit, crtso, _environ, _exit, __exit
.globl begtext, begdata, begbss, endtext, enddata, endbss
.text
begtext:
crtso:		mov	bx,sp
		mov	cx,(bx)
		add	bx,*2
		mov	ax,cx
		inc	ax
		shl	ax,#1
		add	ax,bx
		mov	_environ,ax	| save envp in environ
		push	ax		| push environ
		push	bx		| push argv
		push	cx		| push argc
		mov	ax,#_etext	| monstartup(2, etext)
		push	ax
		mov	ax,#2
		push	ax
		call	_monstartup	| do call of monstartup
		pop	bx		| remove arguments
		pop	bx
		call	_main
		add	sp,*6		| remove arguments
		push	ax		| push exit status
_exit:
		xor	ax,ax		| monitor(0);
		push	ax
		call	_monitor
		pop	bx
__exit:
		push	bp		| this is the exit library call
		mov	bp,sp
		xor	ax,ax
		push	ax
		push	ax
		push	ax
		push	ax
		push	ax
		push	4(bp)
		mov	ax,#1
		push	ax
		xor	ax,ax
		push	ax
		call	_callm1		| this is not supposed to return
.data
begdata:
_environ:	.word	0
.bss
begbss:

SHAR_EOF
fi
echo shar: "extracting 'lib/profil.c'" '(196 characters)'
if test -f 'lib/profil.c'
then
	echo shar: "will not over-write existing file 'lib/profil.c'"
else
cat << \SHAR_EOF > 'lib/profil.c'
#include "../include/lib.h"

PUBLIC int profil(buff, bufsiz, offset, scale)
char *buff;
int bufsiz, offset, scale;
{
  return callm1(MM, PROFIL, bufsiz, offset, scale, buff, NIL_PTR, NIL_PTR);
}

SHAR_EOF
fi
echo shar: "extracting 'man/ast.doc'" '(484 characters)'
if test -f 'man/ast.doc'
then
	echo shar: "will not over-write existing file 'man/ast.doc'"
else
cat << \SHAR_EOF > 'man/ast.doc'
Command:	ast - add symbol table to executable file
Syntax:		ast -xX [file] [symbol_file]
Flags:		-x do not preserve local symbols
		-X preserve local symbols except for those that
		   begin with 'I' or 'L', these are compiler generated
Example:	ast -X a.out	# add symbols from symbol.out to a.out

    Ast adds the symbol table produced by the -s option of asld
to the executable file.  The symbol table is expected in the file symbol.out,
but can also be given at the command line.
SHAR_EOF
fi
echo shar: "extracting 'man/nm.doc'" '(727 characters)'
if test -f 'man/nm.doc'
then
	echo shar: "will not over-write existing file 'man/nm.doc'"
else
cat << \SHAR_EOF > 'man/nm.doc'
Command:	nm - print name list
Syntax:		nm [-gnopru] [file] ...
Flags:		-g print only external symbols.
		-n sort numerically rather than alphabetically.
		-o prepend file name to each line rather than only once.
		-p don't sort, print in symbol-table order.
		-r sort in reverse order.
		-u print only undefined symbols.
Example:	nm -n a.out		# print symbols in numerical order

    Nm prints the symbol table of executable files when it is available.
If no file is given, the symbols in a.out are used.
The format of the table is somewhat compatible with the one produced
by asld when used with the -s option. The symbol table can be added with ast.

NOTE:	archives are not supported, assembly files don't have symbol tables.
SHAR_EOF
fi
echo shar: "extracting 'man/prof.doc'" '(824 characters)'
if test -f 'man/prof.doc'
then
	echo shar: "will not over-write existing file 'man/prof.doc'"
else
cat << \SHAR_EOF > 'man/prof.doc'
Command:	prof - display profile data
Syntax:		prof [-alz] [a.out] [mon.out]
Flags:		-a print all symbols
		-l print symbols by value instead of by percentage
		-z print also symbols with zero count
Example:	prof a.out		# print data collected by a.out

    Prof interprets the mon.out file produced by the monitor subroutine.
The samples are collected, and assigned to the external symbols in the
a.out file.  For each symbol the percentage of time spent in executing
between that symbol and the next are printed.
    Remember that the results are only an aproximation of the real times,
and that short procedures can get to little samples.
Note also that the time spent in send_rec is in fact the time spent
executing the system calls.
    To have the mon.out file automatically produced, use the -p flag
of the C-compiler.
SHAR_EOF
fi
echo shar: "extracting 'man/strip.doc'" '(261 characters)'
if test -f 'man/strip.doc'
then
	echo shar: "will not over-write existing file 'man/strip.doc'"
else
cat << \SHAR_EOF > 'man/strip.doc'
Command:	strip - remove symbol table from executable file
Syntax:		strip [file] ...
Example:	strip a.out		# remove symbols from a.out

    For each file argument, strip removes the symbol table.
Strip makes a copy of the file being stripped, so links are lost.
SHAR_EOF
fi
echo shar: "extracting 'src/ast.c'" '(5892 characters)'
if test -f 'src/ast.c'
then
	echo shar: "will not over-write existing file 'src/ast.c'"
else
cat << \SHAR_EOF > 'src/ast.c'
/* ast - add symbol table.	Author: Dick van Veen, veench@cs.vu.nl */

#include <a.out.h>
#include <stdio.h>

/*
 * Since the a.out file in MINIX does not contain any symbol table,
 * we use the symbol table produced with the -s option of asld.
 *
 * Read symbol table in memory, remove compiler generated labels,
 * sort the labels and add it to the a.out file.
 *
 * When finally there comes a real as and ld, we may also get
 * a symbol table in the a.out file, and we can forget this program.
 *
 */

/*
 * ast [flags] [file] [symbolfile]
 *
 * flags:
 *	-x	do not preserve local symbols
 *	-X	preserve local symbols except for those whose name begin
 *		with 'I' or 'L', these are compiler generated.
 *
 *	-	when no symbol file is present, symbol.out is assumed.
 *	-	when no file is present, a.out is assumed.
 *	-	when one file name is present it must be the executable file
 *	-	just one flag may be pressent.
 *
 */

#define A_OUT		"a.out"
#define SYMBOL_FILE	"symbol.out"	/* contains symbol table */
#define LINE_LENGTH	24

#define WORTH_LESS	1		/* lines contain no symbol */
#define LAST_LINE	2		/* end of file reached */

struct exec header;			/* header info of a.out file */

int x_flag;				/* flags to ast */
int X_flag;
int o_flag;

char *s_file, *o_file;			/* names of files used by ast */
FILE *s_fd, *o_fd;			/* file descriptors of those files */
int nr_symbols;				/* number of symbols added */
char buffer[LINE_LENGTH];		/* contains line of symbol file */

char io_buf[BUFSIZ];			/* for buffered output on stderr */
unsigned int get_value();		/* forward definition */

main(argc, argv)
int argc;
char **argv;
{
	extern FILE *fopen();

	argv++;
	if (*argv != NULL && **argv == '-') {
		*argv += 1;
		if (**argv == 'x') x_flag = 1;
		else if (**argv == 'X') X_flag = 1;
		else {
			fprintf(stderr, "illegal flag: -%c\n", **argv);
			Exit(-1);
		}
		argv++;
	}
	if (*argv != NULL) {
		o_file = *argv;
		argv++;
	}
	if (*argv != NULL) {
		s_file = *argv;
		argv++;
	}
	if (*argv != NULL) {
		fprintf(stderr, "Usage: ast [-{x,X}] [file] [symbolfile]\n");
		Exit(-1);
	}
	if (o_file == NULL) o_file = A_OUT;
	o_fd = fopen(o_file, "a");
	if (o_fd == NULL) {
		fprintf(stderr, "can't open %s\n", o_file);
		Exit(-1);
	}
	if (s_file == NULL) s_file = SYMBOL_FILE;
	s_fd = fopen(s_file, "r");
	if (s_fd == NULL) {
		fprintf(stderr, "can't open %s\n", s_file);
		Exit(-1);
	}
	setbuf(s_fd, io_buf);
	ast(s_fd, o_fd);
	Exit(0);
}

Exit(val)
int val;
{
	_cleanup();
	exit(val);
}

ast(s_fd, o_fd)
FILE *s_fd, *o_fd;
{
	struct nlist symbol;
	int line_type;

	do_header();
	for(;;) {
		read_line(s_fd, buffer);
		line_type = transform_line(buffer, &symbol);
		if (line_type == WORTH_LESS) continue;
		if (line_type == LAST_LINE) break;
		save_line(o_fd, &symbol);
	}
	redo_header(o_fd);
}

read_line(fd, buffer)
FILE *fd;
char *buffer;
{
	char ch;
	char *buf1;

	buf1 = buffer;
	*buffer = '\n';
	ch = fgetc(fd);
	while (ch != '\n' && ch != EOF) {
		*buffer = ch;
		buffer++;
		ch = fgetc(fd);
	}
	if (ch == EOF)
		*buffer = '\0';
	else	*buffer = '\n';
	buffer[1] = '\0';
}

transform_line(buffer, symbol)
char *buffer;
struct nlist *symbol;
{
	switch(*buffer) {
	case 'a':	/* absolute symbol */
		symbol->n_sclass = N_ABS;
		break;
	case 'A':
		symbol->n_sclass = N_ABS | C_EXT;
		break;
	case 'u':	/* undefined symbol */
		symbol->n_sclass = N_UNDF;
		break;
	case 'U':
		symbol->n_sclass = N_UNDF | C_EXT;
		break;

	case 't':	/* text symbol */
		symbol->n_sclass = N_TEXT;
		break;
	case 'T':
		symbol->n_sclass = N_TEXT | C_EXT;
		break;
	case 'd':
		symbol->n_sclass = N_DATA;
	case 'D':	/* data symbol */
		symbol->n_sclass = N_DATA | C_EXT;
		break;
	case 'b':
		symbol->n_sclass = N_BSS;
	case 'B':	/* bss symbol */
		symbol->n_sclass = N_BSS | C_EXT;
		break;
	case '\0':	/* reached end of file */
		return(LAST_LINE);
	default:	/* one of first two lines */
		return(WORTH_LESS);
	}

	if (buffer[1] != ' ') {
		fprintf(stderr, "illegal file format\n");
		Exit(-1);
	}
	symbol->n_value = get_value(buffer + 2);

	if (buffer[6] != ' ') {
		fprintf(stderr, "illegal file format\n");
		Exit(-1);
	}
	get_name(buffer + 7, symbol->n_name);
	return(0);	/* yeah, found a symbol */
}

save_line(fd, symbol)
FILE *fd;
struct nlist *symbol;
{
	if (!(symbol->n_sclass & C_EXT)) {	/* local symbol */
		if (x_flag) return;
		if (X_flag && (symbol->n_name[0] == 'I' ||
			       symbol->n_name[0] == 'L') return;
	}
	if (fwrite(symbol, sizeof(struct nlist), 1, fd) != 1) {
		fprintf(stderr, "can't write %s\n", o_file);
		Exit(-1);
	}
	nr_symbols++;
}

unsigned get_value(string)
char *string;
{
	unsigned value;
	int shift, bits;

	value = 0;
	for (shift = 0; shift < 16; shift += 4) {
		bits = get_bits(*string);
		value = (value << 4) | bits;
		string++;
	}
	return(value);
}

get_bits(ch)
char ch;
{
	if (ch >= '0' && ch <= '9')
		return (ch - '0');
	if (ch >= 'A' && ch <= 'F')
		return (ch - 'A' + 10);
	if (ch >= 'a' && ch <= 'f')
		return (ch - 'a' + 10);
	fprintf(stderr, "illegal file format\n");
	Exit(-1);
}

get_name(str1, str2)
register char *str1, *str2;
{
	int count;

	for (count = 0; count < 8; count++) {
		if (*str1 == '\n') break;
		*str2++ = *str1++;
	}
	while (count < 8) {
		*str2++ = '\0';
		count++;
	}
}

do_header()
{
	int fd;

	fd = open(o_file, 0);
	if (read(fd, &header, sizeof(struct exec)) != sizeof(struct exec)) {
		fprintf(stderr, "%s: no executable file\n", o_file);
		Exit(-1);
	}
	if (BADMAG(header)) {
		fprintf(stderr, "%s: bad header\n", o_file);
		Exit(-1);
	}
	if (header.a_syms != 0L) {
		fprintf(stderr, "%s: symbol table is installed\n", o_file);
		Exit(-1);
	}
	fseek(o_fd, A_SYMPOS(header), 0);
	nr_symbols = 0;
	close(fd);
}

redo_header(fd)
FILE *fd;
{
	header.a_syms = nr_symbols * sizeof(struct nlist);
	fseek(fd, 0L, 0);
	if (fwrite(&header, sizeof(header), 1, fd) != 1) {
		fprintf(stderr, "%s: can't write\n", o_file);
		Exit(-1);
	}
}

SHAR_EOF
fi
echo shar: "extracting 'src/cc1.1.c.diff'" '(897 characters)'
if test -f 'src/cc1.1.c.diff'
then
	echo shar: "will not over-write existing file 'src/cc1.1.c.diff'"
else
cat << \SHAR_EOF > 'src/cc1.1.c.diff'
19a20
> #define SYMBOL_FILE	"symbol.out"		/* symbol table for prof */
77,81c78,81
< struct arglist LD_TAIL = {
< 	2,
< 	{
< 		"/usr/lib/libc.a",
< 		"/usr/lib/end.s"
---
> struct arglist M_LD_HEAD = {
> 	1,
> 	{
> 		"/usr/lib/mrtso.s"
84a85,92
> struct arglist LD_TAIL = {
> 	2,
> 	{
> 		"/usr/lib/libc.a",
> 		"/usr/lib/end.s"
> 	}
> };
> 
115a124
> int p_flag = 0;	/* profil flag */
207d215
< 		case 'p':
210a219,222
> 		case 'p':
> 			p_flag = 1;
> 			append(&ASLD_FLAGS, "-s");
> 			break;
333a346,347
> 		register char *f;
> 
339,342c353,361
< 		concat(call, &LD_HEAD);
< 		concat(call, &LDFILES);
< 		concat(call, &LD_TAIL);
< 		if (runvec(call, (char *)0)) {
---
> 		if (p_flag)
> 			concat(call, &M_LD_HEAD);
> 		else	concat(call, &LD_HEAD);
> 		concat(call, &LDFILES);
> 		concat(call, &LD_TAIL);
> 		if (p_flag) 
> 			f = SYMBOL_FILE;
> 		else	f = (char *) 0;
> 		if (runvec(call, f)) {
SHAR_EOF
fi
echo shar: "extracting 'src/cc1.2.c.diff'" '(1125 characters)'
if test -f 'src/cc1.2.c.diff'
then
	echo shar: "will not over-write existing file 'src/cc1.2.c.diff'"
else
cat << \SHAR_EOF > 'src/cc1.2.c.diff'
20a21,22
> #define SYMBOL_FILE	"symbol.out"		/* symbol table for prof */
> 
31c33
< !!! AH HA!  I HAVE YOUR ATTENTION!
---
> /*!!! AH HA!  I HAVE YOUR ATTENTION!
44c46
< /* #define MEM512K */
---
> #define MEM512K
70,71c72
< 	{
< 		"/usr/lib/crtso.s",
---
> 	{	"/usr/lib/crtso.s"
75,79c76,78
< struct arglist LD_TAIL = {
< 	2,
< 	{
< 		"/usr/lib/libc.a",
< 		"/usr/lib/end.s"
---
> struct arglist M_LD_HEAD = {
> 	1,
> 	{	"/usr/lib/mrtso.s"
82a82,89
> struct arglist LD_TAIL = {
> 	2,
> 	{
> 		"/usr/lib/libc.a",
> 		"/usr/lib/end.s"
> 	}
> };
> 
114a122
> int p_flag = 0;	/* profil flag */
143a152
> 	register char *f;
202d210
< 		case 'p':
205a214,217
> 		case 'p':
> 			p_flag = 1;
> 			append(&ASLD_FLAGS, "-s");
> 			break;
224d235
< 		register char *f;
338,341c349,357
< 		concat(call, &LD_HEAD);
< 		concat(call, &LDFILES);
< 		concat(call, &LD_TAIL);
< 		if (runvec(call, (char *)0)) {
---
> 		if (p_flag)
> 			concat(call, &M_LD_HEAD);
> 		else	concat(call, &LD_HEAD);
> 		concat(call, &LDFILES);
> 		concat(call, &LD_TAIL);
> 		if (p_flag) 
> 			f = SYMBOL_FILE;
> 		else	f = (char *) 0;
> 		if (runvec(call, f)) {
SHAR_EOF
fi
echo shar: "extracting 'src/nm.c'" '(3949 characters)'
if test -f 'src/nm.c'
then
	echo shar: "will not over-write existing file 'src/nm.c'"
else
cat << \SHAR_EOF > 'src/nm.c'
/* nm - print name list.	Author: Dick van Veen, veench@cs.vu.nl */

#include <a.out.h>
#include <stdio.h>

/*
 * Read the name list in memory, sort it, and print it.
 *
 */

/*
 * nm [-gnopru] [file] ...
 *
 * flags:
 *	-g	print only external symbols.
 *	-n	sort numerically rather than alphabetically.
 *	-o	prepend file name to each line rather than only once.
 *	-p	don't sort, print in symbol-table order.
 *	-r	sort in reverse order.
 *	-u	print only undefined symbols.
 *
 *	-	when no file name is present, a.out is assumed.
 *
 *	NOTE:	no archives are supported because assembly files don't
 *		have symbol tables.
 *
 */

#define A_OUT		"a.out"

int g_flag;
int n_flag;
int o_flag;
int p_flag;
int r_flag;
int u_flag;

char io_buf[BUFSIZ];			/* io buffer */
struct exec header;			/* header of a.out file */
int stbl_elems;				/* #elements in symbol table */

main(argc, argv)
int argc;
char **argv;
{
	argv++;
	while (*argv != 0 && **argv == '-') {
		*argv += 1;
		while (**argv != '\0') {
			switch (**argv) {
			case 'g':
				g_flag = 1;
				break;
			case 'n':
				n_flag = 1;
				break;
			case 'o':
				o_flag = 1;
				break;
			case 'p':
				p_flag = 1;
				break;
			case 'r':
				r_flag = 1;
				break;
			case 'u':
				u_flag = 1;
				break;
			default:
				fprintf(stderr, "illegal flag: -%c\n", **argv);
				Exit(-1);
			}
			*argv += 1;
		}
		argv++;
	}
	setbuf(stdin, io_buf);
	if (*argv == 0) nm(A_OUT);
	else while (*argv != 0) {
		nm(*argv);
		argv++;
	}
	Exit(0);
}

Exit(val)
int val;
{
	_cleanup();
	exit(val);
}

nm_sort(stbl1, stbl2)
struct nlist *stbl1, *stbl2;
{
	int cmp;

	if (n_flag) {		/* sort numerically */
		if ((stbl1->n_sclass & N_SECT) < 
		    (stbl2->n_sclass & N_SECT)) cmp = -1;
		else if ((stbl1->n_sclass & N_SECT) >
			 (stbl2->n_sclass & N_SECT)) cmp = 1;
		else if (stbl1->n_value < stbl2->n_value)
			cmp = -1;
		else if (stbl1->n_value > stbl2->n_value)
			cmp = 1;
		else cmp = strncmp(stbl1->n_name, stbl2->n_name, 8);
	} else {
		cmp = strncmp(stbl1->n_name, stbl2->n_name, 8);
		if (cmp == 0) {
			if (stbl1->n_value < stbl2->n_value)
				cmp = -1;
			else if (stbl1->n_value > stbl2->n_value)
				cmp = 1;
		}
	}

	if (r_flag) cmp = -cmp;		/* reverse sort */
	return(cmp);
}

nm(file)
char *file;
{
	struct nlist *stbl;
	int fd;

	fd = open(file, 0);
	if (fd == -1) {
		fprintf(stderr, "can't open %s\n", file);
		return;
	}

	if (read_header(fd)) {
		fprintf(stderr, "%s: no executable file\n", file);
		return;
	}

	stbl = (struct nlist *) malloc((int) (header.a_syms & 0xFFFF));
	if (stbl == NULL) {
		fprintf(stderr, "%s: can't allocate symbol table\n", file);
		return;
	}
	if (read(fd, stbl, (int) (header.a_syms & 0xFFFF))
			!= (int) (header.a_syms & 0xFFFF)) {
		fprintf(stderr, "%s: can't read symbol table\n", file);
		return;
	}
	stbl_elems = (int) header.a_syms/sizeof(struct nlist);
	if (!p_flag) qsort(stbl, stbl_elems, sizeof(struct nlist), nm_sort);
	nm_print(file, stbl);
	close(fd);
}

read_header(fd)
int fd;
{
	if (read(fd, &header, sizeof(struct exec)) != sizeof(struct exec))
		return(1);
	if (BADMAG(header)) return(1);
	lseek(fd, A_SYMPOS(header), 0);

	return(0);
}

nm_print(file, stbl)
char *file;
register struct nlist *stbl;
{
	struct nlist *last;
	char name[9];
	int n_sclass;
	char type;

	name[8] = '\0';
	if (!o_flag) printf("%s:\n", file);
	for (last = &stbl[stbl_elems]; stbl != last; stbl++) {
		if (g_flag && !(stbl->n_sclass & C_EXT)) continue;
		if (u_flag && stbl->n_sclass & N_SECT != N_UNDF) continue;

		n_sclass = stbl->n_sclass & N_SECT;
		if (n_sclass == N_ABS) type = 'a';
		else if (n_sclass == N_TEXT) type = 't';
		else if (n_sclass == N_DATA) type = 'd';
		else if (n_sclass == N_BSS) type = 'b';
		else type = 'u';
		if (stbl->n_sclass & C_EXT) type += 'A' -'a';
		strncpy(name, stbl->n_name, 8);
		if (o_flag) printf("%s:%04X %c %s\n", file, 
				stbl->n_value, type, name);
		else printf("%04X %c %s\n", stbl->n_value, type, name);
	}
}
SHAR_EOF
fi
echo shar: "extracting 'src/prof.c'" '(7444 characters)'
if test -f 'src/prof.c'
then
	echo shar: "will not over-write existing file 'src/prof.c'"
else
cat << \SHAR_EOF > 'src/prof.c'
/* prof - display profile data.	Author: Dick van Veen, veench@cs.vu.nl */

/*
 * Options: 	-a	print all symbols
 *		-l	print symbols by value instead of by percentage
 *		-z	 print also symbols with zero count
 *
 * Note that no graphics are supported.
 *
 */

#include <a.out.h>
#include <stat.h>
#include <stdio.h>

#define A_OUT		"a.out"
#define MON_FILE	"mon.out"
#define SYMBOL_FILE	"symol.out"	/* contains symbol table */

#define MIN(a, b)	((a <= b) ? (a):(b))
#define MAX(a, b)	((a >= b) ? (a):(b))

/* MINIX does not have floating point support, so we use in all calculations
 * the type fixpoint.
 * Fixpoint is a long with 3 decimals, all references to FIXFACTOR are
 * therefore only used to keep the decimals in the right place.
 */
typedef long fixpoint;
#define FIXFACTOR		128
#define TOFIXPOINT(val)		(((long) val) * FIXFACTOR)

/* The mon.out file consists of a header, followed by profheader.nfunc
 * cnt record, the rest of the mon.out file consists of samples.
 */
struct profhdr {			/* header of mon.out file */
	unsigned int lowpc;
	unsigned int highpc;
	int nfunc;
};

struct cnt {				/* structure used for call count */
	int *pc;			/* of functions			 */
	long ncal;
};

struct profhdr profheader;		/* contains mon.out header */
unsigned int *mon_buf;			/* contains samples */

struct symbol {				/* internal symbol representation */
	struct nlist nl;
	fixpoint time;			/* time spent in this ''function'' */
	long ncall;
};
struct symbol *sym_buf;			/* contains internal symbol table */
int symbol_cnt;				/* # of symbols */

struct exec header;			/* contains a.out header */
int samples;				/* number of samples */

int a_flag;				/* flags to prof */
int l_flag;
int z_flag;
char *a_out_file, *mon_out_file;	/* names of files */
fixpoint total_time;			/* count of samples */

char io_buf[BUFSIZ];			/* io buffer */

int sym_cmp(), time_cmp();
unsigned int snr2pc();
extern FILE *fopen();
extern char *calloc();

main(argc, argv)
int argc;
char **argv;
{
	argv++;
	if (*argv != 0 && **argv == '-') {
		*argv += 1;
		while (**argv != 0) {
			if (**argv == 'a')
				a_flag = 1;
			else if (**argv == 'l')
				l_flag = 1;
			else if (**argv == 'z')
				z_flag = 1;
			else fprintf(stderr, "illegal flag: -%c\n", **argv);
			*argv += 1;
		}
		argv++;
	}
	if (*argv == 0) a_out_file = A_OUT;
	else {
		a_out_file = *argv;
		argv += 1;
	}
	if (*argv == 0)
		mon_out_file = MON_FILE;
	else	mon_out_file = *argv;

	read_aout(a_out_file);
	read_monout(mon_out_file);
	print_samples();
	Exit(0);
}

Exit(val)
int val;
{
	_cleanup();		/* may be this gets fixed sometime */
	exit(val);
}

read_aout(file)
char *file;
{
	FILE *fd;

	fd = fopen(file, "r");
	setbuf(fd, io_buf);
	if (fd == NULL) {
		fprintf(stderr, "can't open %s\n", file);
		Exit(-1);
	}
	if (fread(&header, sizeof(struct exec), 1, fd) != 1) {
		fprintf(stderr, "%s: can't read header\n", file);
		Exit(-1);
	}
	if (BADMAG(header)) {
		fprintf(stderr, "%s: no executable file\n", file);
		Exit(-1);
	}
	if (header.a_syms == 0L) {
		fprintf(stderr, "%s: no symbol table\n", file);
		Exit(-1);
	}
	read_symbols(fd, file, header.a_syms);
	fclose(fd);
}

read_symbols(fd, file, size)
FILE *fd;
char *file;
long size;
{
	long length;
	int count;
	struct nlist nsymbol;

	count = 0;
	length = 0L;
	fseek(fd, A_SYMPOS(header), 0);
	while (length < size) {
		length += sizeof(struct nlist);
		if (fread(&nsymbol, sizeof(struct nlist), 1, fd) != 1)
			break;
		if ((nsymbol.n_sclass & N_SECT) != N_TEXT) continue;
		if (!a_flag && !(nsymbol.n_sclass & C_EXT)) continue;
		count++;
	}
	if (length != size) {
		fprintf(stderr, "%s: can't read symbol table\n", file);
		Exit(-1);
	}
	if (count == 0) {
		fprintf(stderr, "%s: no symbols\n", file);
		Exit(-1);
	}
	sym_buf = (struct symbol *) calloc(count+1, sizeof(struct symbol));
	if (sym_buf == NULL) {
		fprintf(stderr,"can't allocate %d bytest for symbol table\n",
			(count + 1) * sizeof(struct symbol));
		Exit(-1);
	}
	fseek(fd, A_SYMPOS(header), 0);
	symbol_cnt = count;
	count = 0;
	while (count < symbol_cnt) {
		fread(&sym_buf[count].nl, sizeof(struct nlist), 1, fd);
		if ((sym_buf[count].nl.n_sclass & N_SECT) != N_TEXT) continue;
		if (!a_flag && !(sym_buf[count].nl.n_sclass & C_EXT)) continue;
		count++;
	}
	qsort(sym_buf, count, sizeof(struct symbol), sym_cmp);
}

read_monout(mon_out)
char *mon_out;
{
	FILE *fd;
	struct stat buf;
	long sample_start;

	fd = fopen(mon_out, "r");
	setbuf(fd, io_buf);
	if (fd == NULL) {
		fprintf(stderr, "can't open %s\n", mon_out);
		Exit(-1);
	}
	if (fread(&profheader, sizeof(struct profhdr), 1, fd) != 1) {
		fprintf(stderr, "%s: can't read header\n", mon_out);
		Exit(-1);
	}
	fstat(fileno(fd), &buf);
	sample_start = sizeof(struct profhdr) +
		profheader.nfunc * sizeof(struct cnt);
	samples = (buf.st_size - sample_start) / sizeof(int);
	read_counts(fd);
	fseek(fd, sample_start, 0);
	assign_samples(fd);
	fclose(fd);
}

read_counts(fd)
int fd;
{
/* No counting code supported yet.
 * Cem produces unusable code with the -p option.
 */
}

assign_samples(fd)
FILE *fd;
{
	unsigned int sample, i, perc;
	unsigned int snr, arealow, areahigh; /* interval covered by sample */
	fixpoint time;
	unsigned int ssize;			/* sample size */
	unsigned scale;
	long tmp;
	unsigned int *tmpptr = (unsigned int *) &tmp;

	total_time = (fixpoint) 0;
						/* recompute scale factor */
	scale = (profheader.highpc - profheader.lowpc);
	if (scale > samples*sizeof(unsigned int)) {
		tmpptr[0] = 0;
		tmpptr[1] = samples*sizeof(unsigned int);
		tmp = tmp / scale;
		scale = tmpptr[0];
	} else {
		scale = 0177777;
	}

	for(snr = 0; fread(&sample, sizeof(sample), 1, fd) == 1; snr++) {
		if (sample == 0) continue;
		arealow  = snr2pc(scale, snr);
		areahigh = snr2pc(scale, snr + 1);
		ssize = areahigh - arealow + 1;
		time = TOFIXPOINT(sample);

		for(i = 0; i < symbol_cnt; i++) {
			if (sym_buf[i].nl.n_value > areahigh) break;
			if (sym_buf[i+1].nl.n_value <= arealow) continue;
			perc = (MIN(areahigh, sym_buf[i+1].nl.n_value) -
				MAX(arealow,  sym_buf[i  ].nl.n_value));
			if (perc > 0) {
				sym_buf[i].time += (((perc+1)*time) / ssize);
			}
		}
		total_time += time;
	}
	if (total_time == (fixpoint) 0) {
		fprintf(stderr, "no samples accumulated\n");
		Exit(-1);
	}
}

unsigned int snr2pc(scale, snr)
unsigned int scale, snr;
{
	long tmp;
	unsigned int *tmpptr = (unsigned int*) &tmp;
	unsigned pc;

	tmpptr[0] = 0;
	tmpptr[1] = snr*sizeof(unsigned);
	tmp = tmp / scale;
	return((tmpptr[0] + profheader.lowpc) & ~1);
}

print_samples()
/* Sort the samples according to the flags and print the result. */
{
	int i;
	char name[9];
	fixpoint time, cumtime;

	name[8] = '\0';
	if (!l_flag)
		qsort(sym_buf, symbol_cnt, sizeof(struct symbol), time_cmp);
	printf("    %%time    cumsecs name\n");
	for (i = 0; i < symbol_cnt; i++) {
		if (!z_flag && sym_buf[i].time == (fixpoint) 0) continue;
		strncpy(name, sym_buf[i].nl.n_name, 8);
		time = ((sym_buf[i].time * 100) * FIXFACTOR) / total_time;
		cumtime += sym_buf[i].time;
		printf("%6D.%03D %6D.%03D %8s\n",
			time / FIXFACTOR,
			time % FIXFACTOR,
			(cumtime / 60) / FIXFACTOR,
			(cumtime / 60) % FIXFACTOR,
			name);
	}
}

int sym_cmp(sym1, sym2)
struct symbol *sym1, *sym2;
{
	return(sym1->nl.n_value - sym2->nl.n_value);
}

int time_cmp(sym1, sym2)
struct symbol *sym1, *sym2;
{
	if (sym1->time < sym2->time) return( 1);
	if (sym1->time > sym2->time) return(-1);
	return(strncmp(sym1->nl.n_name, sym2->nl.n_name, 8));
}
SHAR_EOF
fi
echo shar: "extracting 'src/strip.c'" '(2921 characters)'
if test -f 'src/strip.c'
then
	echo shar: "will not over-write existing file 'src/strip.c'"
else
cat << \SHAR_EOF > 'src/strip.c'
/* strip - remove symbols.	Author: Dick van Veen, veench@cs.vu.nl */

#include <a.out.h>
#include <stdio.h>
#include <stat.h>

/*
 * strip [file] ...
 *
 *	-	when no file is present, a.out is assumed.
 *
 */

#define A_OUT		"a.out"
#define NAME_LENGTH	128		/* max file path name */

char buffer[BUFSIZ];			/* used to copy executable */
char new_file[NAME_LENGTH];		/* contains name of temporary */
struct exec header;

main(argc, argv)
int argc;
char **argv;
{
	argv++;
	if (*argv == NULL) strip(A_OUT);
	else while (*argv != NULL) {
		strip(*argv);
		argv++;
	}
	exit(0);
}

strip(file)
char *file;
{
	int fd, new_fd;
	struct stat buf;

	fd = open(file, 0);
	if (fd == -1) {
		fprintf(stderr, "can't open %s\n", file);
		close(fd);
		return;
	}
	if (read_header(fd)) {
		fprintf(stderr, "%s: not an executable file\n", file);
		close(fd);
		return;
	}
	if (header.a_syms == 0L) {
		close(fd);		/* no symbol table present */
		return;
	}
	header.a_syms = 0L;		/* remove table size */
	fstat(fd, &buf);
	new_fd = make_tmp(new_file, file);
	if (new_fd == -1) {
		fprintf(stderr, "can't create temporary file\n");
		close(fd);
		return;
	}
	if (write_header(new_fd)) {
		fprintf(stderr, "%s: can't write temporary file\n");
		unlink(new_file);
		close(fd);
		close(new_fd);
		return;
	}
	if (copy_file(fd, new_fd, header.a_text + header.a_data)) {
		fprintf(stderr, "can't copy %s\n", file);
		unlink(new_file);
		close(fd);
		close(new_fd);
		return;
	}
	close(fd);
	close(new_fd);
	if (unlink(file) == -1) {
		fprintf(stderr, "can't unlink %s\n", file);
		unlink(new_file);
		return;
	}
	link(new_file, file);
	unlink(new_file);
	chmod(file, buf.st_mode);
}

read_header(fd)
int fd;
{
	if (read(fd, &header, A_MINHDR) != A_MINHDR) return(1);
	if (BADMAG(header)) return(1);
	if (header.a_hdrlen > sizeof(struct exec)) return(1);
	lseek(fd, 0L, 0);		/* variable size header */
	if (read(fd, &header, (int) header.a_hdrlen) != (int) header.a_hdrlen)
		return(1);
	return(0);
}

write_header(fd)
int fd;
{
	lseek(fd, 0L, 0);
	if(write(fd, &header, (int)header.a_hdrlen) != (int)header.a_hdrlen)
		return(1);
	return(0);
}

int make_tmp(new_name, name)
char *new_name, *name;
{
	int len;
	char *nameptr;
	extern char *rindex();

	len = strlen(name);
	if (len + 1 > NAME_LENGTH) return(-1);
	strcpy(new_name, name);
	nameptr = rindex(new_name, '/');
	if (nameptr == NULL) nameptr = new_name-1;
	if (nameptr - new_name + 6 + 1 > NAME_LENGTH) return(-1);
	strcpy(nameptr+1, "XXXXXX");
	mktemp(new_name);
	return(creat(new_name, 0777));
}

copy_file(fd1, fd2, size)
int fd1, fd2;
long size;
{
	long count;
	int length;

	count = 0;
	while (count < size) {
		length = (int) (size - count);
		if (length > sizeof(buffer)) length = sizeof(buffer);
		length = read(fd1, buffer, length);
		if (length == 0) break;
		if (write(fd2, buffer, length) != length) return(1);
		count += length;
	}
	if (count < size) return(1);
	return(0);
}
SHAR_EOF
fi
exit 0
#	End of shell archive