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