[net.sources] V7 object-file crossreference

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

What follows is a distribution for the crossref program.
This version is for Version 7, but another is available
for Unix 4.1BSD.  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 for each external variable
those files which reference it.
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,
is 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
 *
 *	cc -O -n -s -o crossref crossref.c
 *
 *	Produce cross-reference listing from sorted crossref1 file.
 */

#include <stdio.h>
char	ref1[]	"/usr/local/lib/crossref1";
char	sort[]	"sort";
char	file[16], oldsym[8], symbol[8], 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(getline()){
		if(symneq(symbol,oldsym)){
			if (n>0) putchar('\n');
			printf("%.*s",sizeof symbol,symbol);
			n = 0;
			symcopy(symbol,oldsym);
		}
		if(n >= 6){
			n = 0;
			printf("\n        ");
		}
		printf("%10.10s ",file);   /* truncate filename */
		n++;
	}
	putchar('\n');
}

symneq(sym1,sym2)
	register char *sym1,*sym2;
{
	register int i;
	i = 8;
	while(i--) if(*sym1++ != *sym2++) return(1);
	return(0);
}

symcopy(sym1,sym2)
	register char *sym1,*sym2;
{
	register int i;
	i = 8;
	while(i--) *sym2++ = *sym1++;
}

getline() {
	if(getname(symbol,sizeof symbol) == 0) return(0);
	getname(file,sizeof file);
	switch (file[1]) {
	case '<': file[1]='@'; break;
	case '>': file[1]=' '; break;
	case '=': file[1]='#';
	}
	return(getname(thrownc,1));
}

getname(name,count)
	char *name;
	int count;
{
	register int i;
	i = count;
	while(i--) if ((*name++ = getchar())==EOF)  return(0);
	return(1);
}
FuNkYsTuPh
cat > crossref1.c <<FuNkYsTuPh
/*	crossref1.c
 *
 *	cc -O -n -s -o /usr/local/lib/crossref1 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;

FILE	*file;
long	lng;
struct nlist nlist;

main(argc,argv)
	int argc;
	char **argv;
{
	register char *i, *p;
	int argi,flag;

	argi = 0;
newfile:
	if(++argi >= argc) return(0);
	if((file = fopen(argv[argi],"r")) == NULL){
		fprintf(stderr,"can't open %s\n",argv[argi]);
		return(1);
	}
	fread(&flag,sizeof flag,1,file);
	switch (flag) {
	default:
		yell(argv[argi],0);
	case 0177545:
		while ( fread(&arhdr,sizeof arhdr,1,file) == 1) {
			lng = arhdr.ar_size;
			if (strcmp(arhdr.ar_name,"__.SYMDEF")==0) {
				fseek(file,lng+(lng&1),1);
				continue;
			}
			fix(arhdr.ar_name);
			if (aout()) {
			 p = &arhdr.ar_name[sizeof arhdr.ar_name];
			 do { *p-- = '\0';} while (*p==' ');
			 yell(arhdr.ar_name,argv[argi]);
			}
		}
		break;
	case 0406:
	case 0407:
	case 0410:
	case 0411:
		for (i=p=argv[argi]; *i; )
			if (*i++ == '/') p = i;
		for (i=arhdr.ar_name;
			i < &arhdr.ar_name[sizeof arhdr.ar_name] ; )
				*i++ = *p ? (*p=='.'?' ':*p++) : ' ';
		fseek(file,0L,2);
		lng = ftell(file);
		fseek(file,0L,0);
		if (aout()) yell(argv[argi],0);
		break;
	}
	fclose(file);
	goto newfile;
}

aout() {
	int	flag;
	register i;
	fread(&ahdr,sizeof ahdr,1,file);
	switch(ahdr.a_magic) {
		default:	return(1);
		case 0407:
		case 0410:
		case 0411:
				break;
	}
	fseek(file,(long)ahdr.a_text+ahdr.a_data,1);
	lng =- (ahdr.a_text+ahdr.a_data+020);
	if (ahdr.a_flag == 0) {
		fseek(file,(long)ahdr.a_text+ahdr.a_data,1);
		lng =- (ahdr.a_text+ahdr.a_data);
	}
	while ((lng =- 12) >= 0){
		fread(&nlist,sizeof nlist,1,file);
		fixsym(nlist.n_name);
		if(nlist.n_type & N_EXT){
			printf("%-9.8s",nlist.n_name);
			if(nlist.n_type == N_EXT)
				if (nlist.n_value)	putchar('=');
				else			putchar('>');
			else				putchar('<');
			for(i = 0; i < sizeof arhdr.ar_name;i++)
				putchar(arhdr.ar_name[i]);
			putchar('\n');
		}
	}
	return(0);
}

fix(name)
	register char *name;
{
	register char c;
	register int i;
	i = sizeof arhdr.ar_name;
	while(i && (c = *name++) && (c != '.')) i--;
	name--;
	while(i--) *name++ = ' ';
}

fixsym(name)
	register char *name;
{
	register int i;
	i = 8;
	while(i--) if(*name++ == 0) name[-1] = ' ';
}

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