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