Mail Archives: djgpp/1997/04/09/04:52:17
I wrote this Gnu C program (WEEDSYMS.C) to find unused global symbols in a
multi-file djgpp program. To use it:-
(1) Compile all the program's component files with `gcc ... -S' to produce
*.S files. (In the case of the text editor AAEMACS that I wrote, that will
produce files CC.S MAIN.S EM.S DISPLAY.S MACROS.S KEYF.S ZIP.S .)
(2) EITHER call WEEDSYMS.EXE with all these *.S filenames as its args, e.g.
WEEDSYMS CC.S MAIN.S EM.S DISPLAY.S MACROS.S KEYF.S ZIP.S
OR type e.g. WEEDSYMS @ARGFILE
where the file ARGFILE contains all the *.S filenames, one per line.
(3) The list of unused global symbols will now be on the file _.O (in
`mangled' form, if the *.S files were compiled by C++), one per line. If a
symbol started with an underline, that underline is printed out as space, to
produce the correct input form for the demangler CXXFILT.
-------------------------------------------------------
It will not find unused inlined functions (unless you un-inline them by
inserting or #include'ing `#define inline' at the top of each source file).
It will not output line numbers correctly unless the *.S files were
compiled with the -g option.
-------------------------------------------------------
#include<stdio.h>
#include<string.h>
#include<std.h>
#include<sys/stat.h>
#define uns unsigned
/*-----*//* the args should be names of *.S files created by `djgpp -S' */
int main(int nargs,char**arg){
FILE*F; int i,j,k,l,m,n=0; uns short*lnaddr=0;
uns char*sw,**sym; char L[1024],*arg0,*unused,*s;
if(nargs==2) if(arg[1][0]=='@') { /* if the args are on a file */
struct stat B;
arg0=arg[0];
if(stat(sw=arg[1]+1,&B)) {printf("I can't find file `%s'\n",sw); return 1;}
F=fopen(sw,"r"); /* open the file */
sw=(char*)malloc((j=B.st_size)+1); /* make array to hold whole file */
fread(sw,1,j,F); /* read file */
fclose(F);
sw[j]=0;
for(k=i=0;i<j;i++) if(sw[i]=='\n') {sw[i]=0; k++;} /* there are k args */
arg=(char**)malloc(k*sizeof(char*));
arg[0]=arg0;
k=1; /* set up array arg pointing to the args */
if(sw[0]) arg[k++]=sw;
for(i=0;i<j;i++) if(!sw[i]) if(sw[i+1]) arg[k++]=sw+i+1; nargs=k;}
puts("READING DEFINED SYMBOLS");
sym=(uns char**)(malloc(0x10000)); /* allow <= 0x10000 global symbols */
for(m=1;m<nargs;m++) { /* loop for each file */
F=fopen(arg[m],"r"); puts(arg[m]);
while(fgets(L,1024,F),!feof(F)) {
if(!strncmp(L,"\011.def\011",6)) { /* look for line number */
s=strstr(L,".line\011");
if(s) if(lnaddr) {*lnaddr=atoi(s+6); lnaddr=0;}
continue;}
if(!strncmp(L,".globl ",7)) { /* global symbol declaration found */
if((j=strlen(L))) if(L[j-1]=='\n') L[--j]=0; /* remove \n */
sym[n++]=(char*)malloc(j+4); /* list the symbol */
if(j-=7,j>1) strcpy(sym[n-1],L+7); else sym[n-1][0]=0;
sw=sym[n-1]+j;
sw[1]=m; /* it is in the mth file */
sw[2]=sw[3]=0; /* for the line number */
lnaddr=(uns short*)&sw[2];}}
fclose(F);}
for(k=i=n-1;k;i--) for(k=j=0;j<i;j++) if(strcmp(sym[j],sym[j+1])>0) {
sw=sym[j+1]; sym[j+1]=sym[j]; sym[j]=sw; k=1;} /* bubble sort */
for(i=n-1;i>0;i--) if(!strcmp(sym[i-1],sym[i])) sym[i][0]=0;
/* find duplicates */
unused=(char*)malloc(n);
for(i=0;i<n;i++) unused[i]=1;
puts("LOOKING FOR USES OF SYMBOLS");
for(m=1;m<nargs;m++) { /* for each *.S file */
F=fopen(arg[m],"r");
puts(arg[m]); /* tell him how far I've got */
while(fgets(L,1024,F),!feof(F)) /* for each line */
if(L[0]==9) /* ignore label & .globl lines */
if(strncmp(L+1,".def",4)) { /* ignore .def lines */
j=strlen(L);
for(i=0;i<j;i++) if((k=L[i])!='$') if(k!='_') if(k<'0'?:k>'9')
if(k<'0'?:k>'9') if(k<'A'?:k>'Z') if(k<'a'?:k>'z') L[i]=0;
/* replace all non-symbol chars by ascii 0 */
for(i=0;i<j;i++) if(L[i]) if(L[i]!='$') {
/* look for symbols, ignore leading $ */
k=strlen(L+i);
if(L[i]=='_') for(l=0;l<n;l++) if(*sym[l]) if(!strcmp(L+i,sym[l])) {
unused[l]=0; break;} /* if in symbol list, mark as used */
i+=k;}}
fclose(F);}
F=fopen("_.o","w");
fprintf(F,"SYMBOLS DEFINED BUT NOT USED\n");
for(i=0;i<n;i++) if(unused[i]) if((sw=sym[i])[0]) {
if(*sw=='_') fprintf(F," %s",sw+1); else fprintf(F,"%s",sw);
Y: sw+=strlen(sw);
fprintf(F,", in %s, line %1d of source",arg[sw[1]],*(uns short*)(sw+2));
if(i+1<n) if(!sym[i+1][0]) {
sw=sym[++i]; sw[0]='_'; fprintf(F,"\n "); goto Y;}
fprintf(F,"\n");}
fclose(F); free(sym); free(unused); return 0;}
- Raw text -