[net.sources] another crossref program

smh@mit-eddie.UUCP (Steven M. Haflich) (12/22/83)

What follows is a distribution for the crossref program.
This version is for Unix 4.1bsd, but another is available
for Version 7.  To install it, save this mail file somewhere
convenient, edit it to delete everything through the line
of stars below, chmod the file to make it executable, and
start a shell on it.  Three files will be created:
  crossref.1		Manual page
  crossref1.c		The second phase invoked by the crossref
			command.  It should be compiled into
			/usr/local/lib, or wherever local conventions
			dictate.
  crossref.c		The user-invoked command, which should be
			edited if crossref1 goes anywhere other than
			in /usr/local/lib, and then compiled into
			wherever local commands live.
**********************************
cat > crossref.1 <<FuNkYsTuPh
.TH CROSSREF 1
.SH NAME
crossref \- make crossreference listing of object files
.SH SYNOPSIS
.B crossref
object-file ...
.PP
.SH DESCRIPTION
.I Crossref
takes as arguments names of one or more files
which are either object files or archives of object files.
It produces a formatted listing on its standard output
showing those files which reference
each external variable or function name.
If a file defines a size for a variable without initializing it,
the reference is flagged with a
.B #\
\&.
If the variable is initialized as well, the reference
is flagged with a
.B @\
\&.
.PP
This program, invoked on the appropriate files,
can be an important adjunct to grep
for figuring out relations between library modules,
and particularly for demystifying the Unix kernel.
.SH FILES
.ta \w'/usr/local/lib/crossref1  'u
file.o	object file
.br
file.a	object file archive
.br
/usr/local/lib/crossref1	second phase
/bin/sort
.br
/bin/sort
.SH SEE ALSO
A.OUT(V)
FuNkYsTuPh
cat > crossref.c <<FuNkYsTuPh
/*	crossref.c
 *
 *	Produce cross-reference listing from sorted crossref1 output.
 *
 *	The pathname ref1 must be fixed according to local preferences.
 */

#include <stdio.h>
#include <stab.h>

char	ref1[] =	"/usr/local/lib/crossref1";
char	sort[] =	"sort";
char	file[80], oldsym[20], symbol[20], thrownc[1];
int	pip1[2], pip2[2];
int	n;

main(argc,argv) char **argv; {
	register char *p;

	pipe(pip1);
	pipe(pip2);
	if (fork()==0) {
		close(1);
		dup(pip1[1]);
		close(pip1[0]);
		close(pip1[2]);
		close(pip2[0]);
		close(pip2[1]);
		argv[argc] = 0;
		execv(ref1,argv);
		exit(1);
	}
	if (fork()==0) {
		close(0);
		dup(pip1[0]);
		close(1);
		dup(pip2[1]);
		close(pip1[0]);
		close(pip1[1]);
		close(pip2[0]);
		close(pip2[1]);
		execlp(sort,sort,0);
		exit(1);
	}

	close(0);
	dup(pip2[0]);
	close(pip1[0]);
	close(pip1[1]);
	close(pip2[0]);
	close(pip2[1]);

	while (scanf("%19[^<=>]%s\n",symbol,file) == 2) {
		switch (file[0]) {
			case '<': file[0]='@'; break;
			case '>': file[0]=' '; break;
			case '=': file[0]='#';
		}
		if(strcmp(symbol,oldsym)){
			if (n>0) putchar('\n');
			printf("%-12s",symbol);
			n = 0;
			strcpy(oldsym,symbol);
		}
		if(n >= 6){
			n = 0;
			printf("\n            ");
		}
		printf(" %-10s",file);
		n++;
	}
	putchar('\n');
	exit(0);
}
FuNkYsTuPh
cat > crossref1.c <<FuNkYsTuPh
/*	crossref1.c
 *
 *	Print file-symbol pairs for all undefined global
 *	global symbols in a group of objects and object libraries.
 *	This output can be sorted to produce a sort of global
 *	cross reference.
 */

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

struct exec ahdr;
struct ar_hdr arhdr;
char arbuf[SARMAG];

FILE	*file;
char	filename[40];
struct nlist nlist;

streq(p,r,n)
	register char *p, *r;
	register int n;
{
	while (n--) {
		if (*p==0 && *r==0) break;
		if (*p++ != *r++) return(0);
	}
		return(1);
}

main(argc,argv)
	int argc;
	char **argv;
{
	register char *i, *p;
	int argi,flag;
	long base, lng;
	argi = 0;
newfile:
	if(++argi >= argc) return(0);
	if((file = fopen(argv[argi],"r")) == NULL){
		fprintf(stderr,"can't open %s\n",argv[argi]);
		exit(1);
	}
	fread(&flag,sizeof flag,1,file);
	switch (flag) {
	default:
		rewind(file);
		if (	(fread(arbuf,1,SARMAG,file)!=SARMAG)
		 ||	!streq(arbuf,ARMAG,SARMAG))
		 		yell(argv[argi],0);

		while ( fread(&arhdr,sizeof arhdr,1,file) == 1) {
			if (!streq(arhdr.ar_fmag,ARFMAG,2))
		 		yell(argv[argi],0);
			base = ftell(file);
			lng = atoi(arhdr.ar_size);
			if (streq(arhdr.ar_name,"__.SYMDEF ",10)) {
				fseek(file,lng+(lng&1),1);
				continue;
			}
			for (	i=arhdr.ar_name,p=filename; 
				i < &arhdr.ar_name[sizeof arhdr.ar_name] 
					&& *i!=' ';
				*p++ = *i++);		
			*p = '\0';
			if ( (*--p=='.') || (*p=='o' && *--p=='.') ) *p = '\0';
			if (aout()) yell(arhdr.ar_name,argv[argi]);
			fseek(file,base+lng+(lng&1),0);
		}
		break;
	case OMAGIC:
	case NMAGIC:
	case ZMAGIC:
		for (i=p=argv[argi]; *i; )
			if (*i++ == '/') p = i;
		strcpy(filename,p);
		for (p=filename; *p; p++);
		if ( (*--p=='.') || (*p=='o' && *--p=='.') ) *p = '\0';
		fseek(file,0L,0);
		if (aout()) yell(argv[argi],0);
		break;
	}
	fclose(file);
	goto newfile;
}

aout() {
	long baseloc = ftell(file);
	long loc, len, symend;
	char symname[13];

	fread(&ahdr,sizeof ahdr,1,file);
	switch(ahdr.a_magic) {
		default:	return(1);
		case OMAGIC:
		case NMAGIC:
		case ZMAGIC:
				break;
	}
	loc = N_SYMOFF(ahdr);
	symend = N_STROFF(ahdr);
	while (loc < symend) {
		fseek(file, baseloc + loc,0);
		len = fread(&nlist, sizeof nlist, 1, file);
		if (len==0) return(-1);
		loc += sizeof nlist;
		if(nlist.n_type & N_EXT){
			fseek(file, baseloc + symend + nlist.n_un.n_strx,0);
			fscanf(file,"%12s",symname);
			printf("%s",symname);
			if(nlist.n_type == N_EXT)
				if (nlist.n_value)	putchar('=');
				else			putchar('>');
			else				putchar('<');
			printf("%s\n",filename);
		}
	}
	return(0);
}

yell(s,l) char *s, *l; {
	if (l)	fprintf(stderr,"archive %s(%s) not in a.out format\n",l,s);
	else	fprintf(stderr,"%s not in archive or a.out format\n",s);
	exit(1);
}
FuNkYsTuPh