/* * O B J R E F * * NOTE: this program has been superceded by additional capabilities in * nm.c (in tools). It is included here as it offers a simple set of * subroutines for processing symbol tables. */ /*)BUILD $(TKBOPTIONS) = { TASK = ...REF } */ #ifdef DOCUMENTATION title objref Object file cross reference index Object file cross reference synopsis objref file_list description objref reads each file in the list, building a cross reference listing of symbols (where symbols were defined and referenced). .s The files in the file_list were output by nm. The file_list arguments may contain wildcards. The argument string to nm is as follows: .s nm "-1" file.obj >file.nm author Martin Minow bugs Superceded by additional capabilities in nm.c #endif #include #define FALSE 0 #define TRUE 1 #define EOS 0 typedef struct symbol { struct symbol *s_next; char *s_name; struct module *s_defn; /* Where it's defined */ struct refer *s_refer; /* Where it's referenced */ } SYMBOL; typedef struct module { struct module *m_next; char *m_name; int m_index; } MODULE; typedef struct refer { struct refer *r_next; struct module *r_module; } REFERENCE; SYMBOL *sfirst = NULL; MODULE *mfirst = NULL; REFERENCE *rfirst = NULL; FILE *fd; char line[133]; char name[133]; char value[133]; #define CROSS_MAX 25 int cross[CROSS_MAX][CROSS_MAX]; char *mname[CROSS_MAX]; int cmax = -1; extern char *strsave(); extern char *myalloc(); main(argc, argv) int argc; char *argv[]; { register int nfiles; register int i; for (i = 1; i < argc; i++) { if ((fd = fwild(argv[i], "r")) == NULL) { fprintf(stderr, "can't open wild card file: "); perror(argv[i]); continue; } for (nfiles = 0; fnext(fd) != NULL; nfiles++) { process(); } if (nfiles == 0) { fprintf(stderr, "no files match \"%s\"\n", argv[i]); } } mnames(); output(); } process() /* * For each file ... */ { register MODULE *mp; register SYMBOL *sy; extern MODULE *newmodule(); extern SYMBOL *lookup(); getfilename(fd, line); mp = newmodule(line); while (fgets(line, sizeof line, fd) != NULL) { sscanf(line, "%s%*s%s", &name, &value); sy = lookup(name); if (value[0] == '*') { addref(sy, mp); /* Undefined here */ } else { /* Defined here */ if (sy->s_defn != NULL) { printf("** symbol %s defined in %s and %s\n", sy->s_name, (sy->s_defn)->m_name, mp->m_name); fprintf(stderr, "** symbol %s defined in %s and %s\n", sy->s_name, (sy->s_defn)->m_name, mp->m_name); } else { sy->s_defn = mp; } } } } output() { register SYMBOL *sy; register int nsy; register REFERENCE *rp; int i, j; /* * Pass 1 for "library" symbols only */ printf("The following are not defined:\n"); nsy = 0; for (sy = sfirst; sy != NULL; sy = sy->s_next) { if (sy->s_defn == NULL) { printf("%c%s", ((nsy & 7) == 0) ? '\n' : '\t', sy->s_name); nsy++; } } printf("\n\n"); /* * Pass 2 for symbols not used elsewhere */ printf("The following are not used outside of their module:\n"); nsy = 0; for (sy = sfirst; sy != NULL; sy = sy->s_next) { if (sy->s_defn != NULL && sy->s_refer == NULL) { printf("%c%s\t%s", ((nsy & 3) == 0) ? '\n' : '\t', sy->s_name, (sy->s_defn)->m_name); nsy++; } } /* * Pass 3 -- all the rest */ printf("\n\nThe following are defined and used elsewhere\n"); for (sy = sfirst; sy != NULL; sy = sy->s_next) { if (sy->s_defn == NULL || sy->s_refer == NULL) { continue; } i = (sy->s_defn)->m_index; printf("\n%s\t%s:", sy->s_name, (sy->s_defn)->m_name); nsy = 0; for (rp = sy->s_refer; rp != NULL; rp = rp->r_next) { printf("%s%s", ((++nsy % 6) == 0) ? "\n\t\t" : "\t", (rp->r_module)->m_name); j = (rp->r_module)->m_index; cross[i][j]++; } } printf("\n"); /* * Now for the map */ printf("\nmodule"); for (i = 0; i <= cmax; i++) { printf("\n%s\t", mname[i]); for (j = 0; j < i; j++) { printf("%4d", cross[i][j] + cross[j][i]); } printf(" %s", mname[i]); } } /* * Manage symbol table */ MODULE * newmodule(text) /* * Make this a new module entry. */ { register MODULE *mp; register MODULE **mplast; register MODULE *new; int i; new = myalloc(sizeof (MODULE)); new->m_name = strsave(text); for (mplast = &mfirst; (mp = *mplast) != NULL; mplast = &mp->m_next) { if ((i = strcmp(text, mp->m_name)) < 0) break; else if (i == 0) { fprintf(stderr, "duplicate module name \"%s\"\n", text); return(mp); } } new->m_next = mp; *mplast = new; cmax++; if (cmax >= CROSS_MAX) error("too many modules"); return(new); } addref(sy, mp) SYMBOL *sy; MODULE *mp; /* * The module references this symbol. */ { register REFERENCE *rp; REFERENCE **rplast; register REFERENCE *new; register int i; new = myalloc(sizeof (REFERENCE)); new->r_module = mp; for (rplast = &sy->s_refer; (rp = *rplast) != NULL; rplast = &rp->r_next) { if ((i = strcmp(mp->m_name, (rp->r_module)->m_name)) == 0) { fprintf(stderr, "\"%s\" references \"%s\" twice\n", sy->s_name, mp->m_name); } else if (i < 0) { break; } } new->r_next = rp; *rplast = new; } SYMBOL * lookup(text) char *text; /* * Return pointer to this symbol, insert if new */ { register SYMBOL *sy; SYMBOL **sylast; register SYMBOL *new; register int i; for (sylast = &sfirst; (sy = *sylast) != NULL; sylast = &sy->s_next) { if ((i = strcmp(text, sy->s_name)) == 0) { return(sy); } else if (i < 0) { break; } } new = myalloc(sizeof (SYMBOL)); new->s_name = strsave(text); new->s_next = sy; *sylast = new; return (new); } mnames() /* * Build mname[] vector */ { register int i; register MODULE *mp; i = 0; for (mp = mfirst; mp != NULL; mp = mp->m_next, i++) { mname[i] = mp->m_name; mp->m_index = i; } } /* * Support routines */ getfilename(filedes, buffer) FILE *filedes; char *buffer; { register char *tp; register char c; fgetname(filedes, buffer); /* * Skip over device name */ for (tp = buffer; (c = *tp) != EOS && c != ':'; tp++); if (c) tp++; else tp = buffer; /* * Skip over [UIC] or * or [PPN] if present */ if (*tp == '[' || *tp == '(') { while ((c = *tp++) && c != ']' && c != ')'); if (c == 0) { error("Can't happen"); tp--; } } strcpy(buffer, tp); /* * Don't include version */ for (tp = buffer; (c = *tp) && c != ';'; tp++); *tp = 0; /* * Don't include .ext */ for (tp = buffer; (c = *tp) && c != '.'; tp++); *tp = 0; /* * Now, buffer has the file name, * tp - buffer, its length. */ return(buffer); } char * strsave(text) char *text; /* * Save this text */ { register char *p; if ((p = malloc(strlen(text) + 1)) == NULL) error("No room for string alloc."); strcpy(p, text); return (p); } char * myalloc(size) int size; /* * Allocate or die */ { register char *p; if ((p = calloc(1, size)) == NULL) { fprintf(stderr, "Can't allocate %d bytes\n", size); error("Fatal"); } return (p); }