home *** CD-ROM | disk | FTP | other *** search
- From: m_mcdonald@vaxa.uwa.oz
- Newsgroups: alt.sources
- Subject: object module dependancy cycle tool
- Message-ID: <1990Jun21.151207.1916@vaxa.uwa.oz>
- Date: 21 Jun 90 07:12:07 GMT
-
- /*
- This program detects dependency cycles in object modules
- preventing them being sorted into a standard 1 pass library.
-
- Unlike "lorder *.o | tsort" which does tell you about
- object modules in dependency cycles, cyc.c will explain exactly
- *which* labels are causing the cycles.
-
- There is perhaps a better way of doing this but I didn't know
- about it when I wrote this and I still don't.
- It's ugly and slow and will probably need mods if you have
- a different nm.
- However it saved me a lot of time looking for cycles in
- 10 object files where each file had 100-400 external labels.
-
- If you all know a better way, sorry to be wasting bandwidth,
- mail me and let me know.
- Matthew McDonald.
-
- */
- /*
- * cyc.c - detect causes of dependency cycles in object modules
- *
- * and print names of the offending labels.
- *
- * - Matthew McDonald 19/06/90
- *
- * *very* nm specific
- * - currently only useful for (prime 386) sys V nm
- * History:
- *
- *
- *
- */
-
-
- #include <stdio.h>
- #include <string.h>
- #include <malloc.h>
-
- extern int exit();
- extern char *strchr();
-
-
- #define MAXOBJECT 120 /* Max object files in dependency cycle */
- #define MAXFILENAME 40 /* Max filename size */
- #define MAXLABELS 800 /* # Labels per module we can cope with */
- #define COMMANDSIZE 50 /* Size of biggest command we'll make */
-
- #define NM_DASH_U_JUNK_LINES 6 /* Number of junk lines in nm -u output */
- #define NM_JUNK_LINES 5 /* Number of junk lines in ordinary
- * nm output */
- #define NMOUTPUTWIDTH 80 /* Assume all nm output <= 80 chars */
- #define SECTION_FIELD 6 /* 'Section' is the 6th field of nm output */
- #define NM_FIELD_SEP '|' /* nm output field separator */
- #define NM_DASH_U_LABEL_START 4
-
- char *progname; /* argv[0] */
- char objnames[MAXOBJECT][MAXFILENAME]; /* Names of object files */
-
- int num_def[MAXOBJECT]; /* Number of Labels defined */
- char *def_name[MAXOBJECT][MAXLABELS];/* Their names */
-
- int num_req[MAXOBJECT]; /* Number of Labels required */
- char *req_name[MAXOBJECT][MAXLABELS];/* Their names */
- int num_objs;
-
- char dependant[MAXOBJECT][MAXOBJECT];/* Dependancy matrix */
-
- char buffer[NMOUTPUTWIDTH+1]; /* input/error message buffer */
-
-
- void fatal(msg)
- char *msg;
- /* Crash out */
- {
- fprintf(stderr,"%s: %s\n",progname,msg);
- exit(1);
- }
-
- char *newstring(size)
- int size;
- /* get a memory for a string - crash on failure */
- {
- char *value;
-
- value = malloc(size+1);
- if(!value)
- fatal("out of memory");
-
- return value;
- }
-
- void junk_nls(str)
- char *str;
- /* Remove trailing '\n's */
- {
-
- while(str[strlen(str)-1]=='\n')
- str[strlen(str)-1]=0;
- }
-
- void get_names()
- /* Get names of object files - quite after "." */
- {
- int i;
-
- for(i=1; i<(MAXOBJECT+1); i++){
- scanf("%s",objnames[i]);
- if(!strcmp(objnames[i],"."))
- break;
- }
-
- num_objs = i;
- }
-
- #ifdef DEBUG
- void print_requireds()
- /* For each object file print required labels - debugging */
- {
- int i, j;
-
-
- for(i=num_objs;--i;){
- printf("File %s needs :\n",objnames[i]);
- for(j=0;j<num_req[i];j++)
- printf("%d)'%s'\n",j,req_name[i][j]);
- }
- }
-
- void print_defineds()
- /* For each of the files print defined labels - debugging */
- {
- int i, j;
-
- for(i=num_objs;--i;){
- printf("File %s defines :\n",objnames[i]);
- for(j=0; j <num_def[i]; j++)
- printf("%d)'%s'\n",j,def_name[i][j]);
- }
- }
- #endif
-
- static int first_obj;
-
- void print_dependancy(needer, definer)
- int needer;
- int definer;
- {
- int x, y;
-
- for(x=0;x<num_req[needer];x++){
- #ifdef DEBUG
- printf("checking %s's required label (%d)%s against:\n",
- objnames[needer],x,req_name[definer][x]);
- #endif
- for(y=0;y<num_def[definer];y++){
- #ifdef DEBUG
- printf("\t%s's defined label (%d)%s\n",
- objnames[definer],y,def_name[definer][y]);
- #endif
- if(!strcmp(req_name[needer][x],def_name[definer][y]))
- printf("\t%s\n", req_name[needer][x]);
- }
- }
- }
-
- int check_cycle2(obj)
- int obj;
- {
- int i;
-
- /* Detected a cycle, should only happen in check_cycle2()
- * since no object file should depend on itself
- */
- if(dependant[obj][first_obj]){
- printf("%s depends on %s for label(s)\n",
- objnames[obj],objnames[first_obj]);
- print_dependancy(obj,first_obj);
- return 1;
- }
- for(i=num_objs;--i;)
- if(dependant[obj][i])
- if(check_cycle2(i)){
- printf("%s depends on %s for label(s):\n",
- objnames[obj],objnames[i]);
- print_dependancy(obj,i);
- return 1;
- }
- /* No cycles */
- return 0;
- }
-
- int check_cycle(obj)
- int obj;
- {
- int i;
-
- first_obj = obj;
-
- /* Detected a cycle, should only happen in check_cycle2()
- * since no object file should depend on itself
- */
- if(dependant[obj][first_obj]){
- printf("%s depends on %s for label(s):\n",
- objnames[obj],objnames[first_obj]);
- print_dependancy(obj,first_obj);
- fatal("Internal error - object depends on itself");
- }
-
- for(i=num_objs;--i;)
- if(dependant[obj][i])
- if(check_cycle2(i)){
- printf("%s depends on %s for label(s):\n",
- objnames[obj],objnames[i]);
- print_dependancy(obj,i);
- return 1;
- }
- /* No cycles */
- return 0;
- }
-
- void find_dependencies()
- /* Fill in the dependency matrix */
- {
- int i, j,x, y;
-
-
- /* Figure out the dependencies of the named files */
- for(i=num_objs;--i;){
- for(j=num_objs;--j;){
- if(i==j)
- /* Nothing requires a label defined by itself */
- continue;
- for(x=0;x<num_req[i];x++){
- #ifdef DEBUG
- printf("checking %s's required label (%d)%s against:\n",
- objnames[i],x,req_name[i][x]);
- #endif
- for(y=0;y<num_def[j];y++){
- #ifdef DEBUG
- printf("\t%s's defined label (%d)%s\n",
- objnames[j],y,def_name[j][y]);
- #endif
- if(!strcmp(req_name[i][x],def_name[j][y])){
- /* object i depends on object j for req[x] */
- #ifdef DEBUG
- printf(" debug: %s depends on %s for label %s\n",
- objnames[i],objnames[j],req_name[i][x]);
- #endif
- dependant[i][j]=1;
- }
- }
- }
- }
- }
- }
-
- void get_required_labels()
- /* For each of the files get required labels */
- {
-
- char command[COMMANDSIZE];
- FILE *instream;
- int i,j;
- int label=0;
-
-
- for(i=num_objs;--i;){
- sprintf(command,"nm -u %s",objnames[i]);
- instream=popen(command,"r");
- if(!instream){
- sprintf(buffer,"could not exec %s\n",command);
- fatal(buffer);
- }
- /* Throw away unwanted nm output */
- for(j=0;j<NM_JUNK_LINES;j++)
- fgets(buffer,NMOUTPUTWIDTH,instream);
- while(fgets(buffer,NMOUTPUTWIDTH,instream)){
- if(label==MAXLABELS)
- fatal("too many labels in object file");
- junk_nls(buffer);
- req_name[i][label]=newstring(strlen(buffer)-
- NM_DASH_U_LABEL_START);
- strcpy(req_name[i][label],buffer+4);
- label++;
- }
- pclose(instream);
- num_req[i]=label;
- label = 0;
- }
- }
-
- char *section_field(str)
- char *str;
- /* Return pointer to 'Section' field of an nm output line */
- {
- char *tmp;
- int i;
-
- tmp=strchr(str,NM_FIELD_SEP);
-
- for(i=0; i < (SECTION_FIELD-1); i++)
- tmp=strchr(tmp+1,NM_FIELD_SEP);
-
- return tmp+1;
- }
-
- int is_definition_section(section)
- char *section;
- /* Does this section field mean label is definition or merely a
- * reference to one */
- {
- /* with sys V nm, a '.' in 1st char of the section field virtually
- * gaurantees that the label is defined in this module.
- * Possibly the comparison should be against ".text", ".data", ".bss"
- * and ".common" - but a "." seems to work fine for me.
- */
- return *section=='.';
- }
-
- char *nm_output_to_label(line)
- char *line;
- /* convert an nm output line to the label contained in it by
- * finding the end of the label making it zero -
- * return the label
- */
- {
- char *tmp1, *tmp2;
-
- tmp2 = strchr(buffer,' ');
- tmp1 = strchr(buffer,NM_FIELD_SEP);
- tmp1 = ( (tmp1<tmp2) ? tmp1 : tmp2);
- *tmp1 = 0;
- return line;
- }
-
- void get_defined_labels()
- /* For each of the files get defined labels */
- {
- char command[COMMANDSIZE];
- FILE *instream;
- int i,j;
- int label=0;
- char *tmp;
-
- for(i=num_objs;--i;){
- sprintf(command,"nm %s",objnames[i]);
- instream=popen(command,"r");
- if(!instream){
- sprintf(buffer,"could not exec %s\n",command);
- fatal(buffer);
- }
- /* Throw away unwanted nm output */
- for(j=0; j<NM_DASH_U_JUNK_LINES; j++)
- fgets(buffer,NMOUTPUTWIDTH,instream);
- while(fgets(buffer,NMOUTPUTWIDTH,instream)){
- if(label==MAXLABELS)
- fatal("too many labels in object file");
- junk_nls(buffer);
- tmp=section_field(buffer);
- if(is_definition_section(tmp)){
- tmp = nm_output_to_label(buffer);
- def_name[i][label]=newstring(strlen(tmp));
- /* Copy the label to definitions list */
- strcpy(def_name[i][label++],tmp);
- }
- }
- pclose(instream);
- num_def[i]=label;
- label = 0;
- }
- }
-
-
- int main(argc, argv)
- int argc;
- char **argv;
- {
-
- int i;
-
- /* set up for error messages */
- progname = argv[0];
-
- get_names();
- get_required_labels();
- # ifdef DEBUG
- print_requireds();
- # endif
- get_defined_labels();
- # ifdef DEBUG
- print_defineds();
- # endif
- find_dependencies();
- for(i=num_objs;--i;)
- if (check_cycle(i))
- exit(0);
- /*not very*/ fatal("no cycles exist\n");
-
- return 0; /* lint */
- }
-